题目描述

涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度。 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: ∑(ai-bi)^2

其中 ai 表示第一列火柴中第 i 个火柴的高度,bi 表示第二列火柴中第 i 个火柴的高度。

每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 99,999,997 取模的结果。

输入输出格式

输入格式:

输入文件为 match.in。

共三行,第一行包含一个整数 n,表示每盒中火柴的数目。

第二行有 n 个整数,每两个整数之间用一个空格隔开,表示第一列火柴的高度。

第三行有 n 个整数,每两个整数之间用一个空格隔开,表示第二列火柴的高度。

输出格式:

输出文件为 match.out。

输出共一行,包含一个整数,表示最少交换次数对 99,999,997 取模的结果。

输入输出样例

输入样例#1:

【输入输出样例 1】
4
2 3 1 4
3 2 1 4
【输入输出样例 2】
4
1 3 4 2
1 7 2 4
输出样例#1:

【输入输出样例 1】
1
【输入输出样例 2】
2

说明

【输入输出样例说明1】

最小距离是 0,最少需要交换 1 次,比如:交换第 1 列的前 2 根火柴或者交换第 2 列的前 2 根火柴。

【输入输出样例说明2】

最小距离是 10,最少需要交换 2 次,比如:交换第 1 列的中间 2 根火柴的位置,再交换第 2 列中后 2 根火柴的位置。

【数据范围】

对于 10%的数据, 1 ≤ n ≤ 10;

对于 30%的数据,1 ≤ n ≤ 100;

对于 60%的数据,1 ≤ n ≤ 1,000;

对于 100%的数据,1 ≤ n ≤ 100,000,0 ≤火柴高度≤ maxlongint

这个题贪心的证明

假设第一列有两个数 a,b(a < b) 第二列有两个数 x,y(x < y)

那么看(a-x)^2+(b-y)^2与(a-y)^2+(b-x)^2哪个更小,哪个就更优

可以假设左边<右边,然后化简,将两边的二次方都去掉

化简后得 -ax-by < -ay-bx

再次移项得到 a(x-y)>b(x-y) 由于x-y是负数,化简后得 a < b,式子成立(意思就是如果左边>右边的话就与条件矛盾了)

那么显然小的配小的,大的配大的最优

那么我们目标就是a的第一大和b的第一大在一块,a的第i大和b的第i大在一块

那么我们可以固定一端移动另外一端,

固定a移动b,那么我们发现移动的时候按b的第几大为关键字进行移动,那么值为1的数不一定要移动到1这个位置

因为1这个下标索引不一定是a的第一大

所以我们发现一个显然成立的事实,那就是从一个乱序数组排序成有序数组的最少交换次数和一个有序数组还原成乱序数组的最小交换次数相同

那么就相当于,当前已经按目标位置排好序的序列到原位置的最少交换次数=原序列到各自移动到目标位置的序列的最少交换次数

因为等式右边难于实现,所以选择等价的左边的实现,先让他跑到应该到的位置,然后跑回原位,这就是解决方法(有点像时光倒流哦

附上代码 (套自己的模板所以有点长

 1 #include <iostream>
2 #include <cstdio>
3 #include <algorithm>
4 #include <cstring>
5 using namespace std;
6 const int maxn=1e5+7;
7 int N,w;
8 typedef long long ll;
9 ll t[maxn],q[maxn];
10 struct node{
11 int id,v;node(){};node(int id,int v):id(id),v(v){};
12 };
13 node a[maxn],b[maxn];
14 int lowbit(int x){
15 return x&-x;
16 }
17 void add(int n,int x){
18 while(n<=N){
19 t[n]+=x;
20 n+=lowbit(n);
21 }
22 }
23 ll sum(int n){
24 ll ans=0;
25 while(n){
26 ans=(ans+t[n]);
27 n-=lowbit(n);
28 }
29 return ans;
30 }
31 bool cmp1(node a,node b){
32 return a.v<b.v;
33 }
34 bool cmp2(node a,node b){
35 return a.id<b.id;
36 }
37 int main(){
38 int n,x;scanf("%d",&n);
39 for(int i=1;i<=n;++i){
40 scanf("%d",&x);
41 a[i]=node(i,x);
42 }
43 for(int i=1;i<=n;++i){
44 scanf("%d",&x);
45 b[i]=node(i,x);
46 }
47 sort(a+1,a+1+n,cmp1);
48 sort(b+1,b+1+n,cmp1);
49 int cnt=1,st=1,pre=a[1].v;
50 for(int i=2;i<=n;++i){
51 while(i<=n&&a[i].v==pre) i++;
52 for(int j=st;j<i;++j){
53 a[j].v=cnt;
54 }
55 st=i;pre=a[i].v;
56 cnt++;
57 }
58 for(int j=st;j<=n;++j) a[j].v=cnt;
59 //for(int i=1;i<=n;++i) printf("%d,",a[i].v);printf("\n");
60 cnt=1,st=1,pre=b[1].v;
61 for(int i=2;i<=n;++i){
62 while(i<=n&&b[i].v==pre) i++;
63 for(int j=st;j<i;++j){
64 b[j].v=cnt;
65 }
66 st=i;pre=b[i].v;
67 cnt++;
68 }
69 for(int j=st;j<=n;++j) b[j].v=cnt;
70 //for(int i=1;i<=n;++i) printf("%d,",b[i].v);printf("\n");
71 //sort(a+1,a+1+n,cmp2);sort(b+1,b+1+n,cmp2);
72 N=n;
73 for(int i=1;i<=n;++i){
74 q[a[i].id]=b[i].id;//也就是说,当前排名相同的两个位置,b[i].id的目标位置是a[i].id,
75 }
76 ll ans=0;
77 for(int i=n;i>=1;--i){
78 ans=(ans+sum(q[i]-1))%99999997;
79 add(q[i],1);
80 }
81 printf("%lld\n",ans);
82 return 0;
83 }

为什么按值排序呢,因为我们要对排名相同的配对,这是我们要的目标序列

洛谷p1966 火柴排队 (逆序对变形,目标排序的更多相关文章

  1. 洛谷P1966 火柴排队(逆序对)

    题意 题目链接 Sol 不算很难的一道题 首先要保证权值最小,不难想到一种贪心策略,即把两个序列中rank相同的数放到同一个位置 证明也比较trivial.假设\(A\)中有两个元素\(a, b\), ...

  2. [NOIP2013提高&洛谷P1966]火柴排队 题解(树状数组求逆序对)

    [NOIP2013提高&洛谷P1966]火柴排队 Description 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相 ...

  3. 【刷题】洛谷 P1966 火柴排队

    题目描述 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: ∑(ai-bi)^2 其中 ai 表示 ...

  4. 洛谷 P1966 火柴排队 解题报告

    P1966 火柴排队 题目描述 涵涵有两盒火柴,每盒装有 \(n\) 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: \(\s ...

  5. luogu P1966 火柴排队 (逆序对)

    luogu P1966 火柴排队 题目链接:https://www.luogu.org/problemnew/show/P1966 显然贪心的想,排名一样的数相减是最优的. 证明也很简单. 此处就不证 ...

  6. 洛谷——P1966 火柴排队&&P1774 最接近神的人_NOI导刊2010提高(02)

    P1966 火柴排队 这题贪心显然,即将两序列中第k大的数的位置保持一致,证明略: 树状数组求逆序对啦 浅谈树状数组求逆序对及离散化的几种方式及应用 方法:从前向后每次将数插入到bit(树状数组)中, ...

  7. P1966 火柴排队——逆序对(归并,树状数组)

    P1966 火柴排队 很好的逆序对板子题: 求的是(x1-x2)*(x1-x2)的最小值: x1*x1+x2*x2-2*x1*x2 让x1*x2最大即可: 可以证明将b,c数组排序后,一一对应的状态是 ...

  8. P1966 火柴排队(逆序对)

    P1966 火柴排队 题目描述 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: ∑(ai-bi) ...

  9. 洛谷P1966 火柴排队 贪心+离散化+逆序对(待补充QAQ

    正解: 贪心+离散化+逆序对 解题报告: 链接在这儿呢quq 这题其实主要难在想方法吧我觉得?学长提点了下说用贪心之后就大概明白了,感觉没有很难 但是离散化这里还是挺有趣的,因为并不是能很熟练地掌握离 ...

  10. NOIP 2013 洛谷P1966 火柴排队 (树状数组求逆序对)

    对于a[],b[]两个数组,我们应选取其中一个为基准,再运用树状数组求逆序对的方法就行了. 大佬博客:https://www.cnblogs.com/luckyblock/p/11482130.htm ...

随机推荐

  1. uni-app开发经验分享六:页面跳转及提示框

    在我们开发的uni-app的过程中,页面跳转及提示框往往是我们做数据交互及结果反馈所要使用的功能,这里分享下我收集的一些方法及看法. 一:页面跳转 事件跳转 :指通过tap等事件来实现页面的跳转,跳转 ...

  2. kvm实战

    1. 安装环境 # yum install qemu-kvm libvirt virt-install virt-manager virt-viewer -y # systemctl start li ...

  3. 前端面试之ES6新增了数组中的的哪些方法?!

    前端面试之ES6新增了数组中的的哪些方法?! 我们先来看看数组中以前有哪些常用的方法吧! 1 新增的方法! 1 forEach() 迭代遍历数组 回调函数中的三个参数 value: 数组中的每一个元素 ...

  4. Promise用法

    1.概述 Promise是一步编程的一种解决方案,从语法上讲,promise是一个对象,从它可以获取异步的问题 Promise的优点: 可以避免多次异步调用嵌套导致的回调地域 提供了简洁的api,使得 ...

  5. 如何应对C语言内存泄露! 华为开发者社区 2020-09-29

    如何应对C语言内存泄露! 华为开发者社区 2020-09-29

  6. GRASP职责分配模式

    https://mp.weixin.qq.com/s/IaxAnWfVqe3mM0bHFVV5Gg 软件开发必修课:你该知道的GRASP职责分配模式 原创 悟真 阿里技术 今天 收录于话题 #设计模式 ...

  7. python基础(格式化输出、基本运算符、编码)

    1,格式化输出. 现有一练习需求,问用户的姓名.年龄.工作.爱好 ,然后打印成以下格式 ------------ info of Alex Li ----------- Name : Alex Li ...

  8. LOJ10075 农场派对

    USACO 2007 Feb. Silver N(1≤N≤1000) 头牛要去参加一场在编号为 x(1≤x≤N) 的牛的农场举行的派对.有 M(1≤M≤100000) 条有向道路,每条路长Ti​(1≤ ...

  9. 八:SpringBoot-集成JPA持久层框架,简化数据库操作

    SpringBoot-集成JPA持久层框架,简化数据库操作 1.JPA框架简介 1.1 JPA与Hibernate的关系: 2.SpringBoot整合JPA Spring Data JPA概述: S ...

  10. Linux环境Hive安装配置及使用

    Linux环境Hive安装配置及使用 一.Hive Hive环境前提 二.Hive架构原理解析 三.Hive-1.2.2单机安装流程 (1) 解压apache-hive-1.2.2-bin.tar.g ...