洛谷 P1966 火柴排队 题解
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 P1966 火柴排队 题解相关的知识,希望对你有一定的参考价值。
此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置。
题目链接:https://www.luogu.org/problem/show?pid=1966
题目描述
涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度。 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: ∑(ai-bi)^2
其中 ai 表示第一列火柴中第 i 个火柴的高度,bi 表示第二列火柴中第 i 个火柴的高度。
每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 99,999,997 取模的结果。
输入输出格式
输入格式:输入文件为 match.in。
共三行,第一行包含一个整数 n,表示每盒中火柴的数目。
第二行有 n 个整数,每两个整数之间用一个空格隔开,表示第一列火柴的高度。
第三行有 n 个整数,每两个整数之间用一个空格隔开,表示第二列火柴的高度。
输出格式:输出文件为 match.out。
输出共一行,包含一个整数,表示最少交换次数对 99,999,997 取模的结果。
输入输出样例
4 2 3 1 4 3 2 1 4
1
4 1 3 4 2 1 7 2 4
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中次大……
对a,b按照从小到大分别排序,进行一个类似离散化的操作,然后用rank[a[i].ord] = b[i].ord进行对应。
对rank数组求逆序对即可。这里用了树状数组,也可以归并排序。
2017.11.8更新:补上归并排序的代码。
AC代码:
1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 #include<cstring> 5 6 const int MOD = 99999997; 7 const int MAXN = 100005; 8 9 inline void read(int &x) 10 { 11 char ch = getchar(),c = ch;x = 0; 12 while(ch < ‘0‘ || ch > ‘9‘) c = ch,ch = getchar(); 13 while(ch <= ‘9‘ && ch >= ‘0‘) x = (x<<1)+(x<<3)+ch-‘0‘,ch = getchar(); 14 if(c == ‘-‘) x = -x; 15 } 16 17 int n,rank[MAXN]; 18 long long ans; 19 20 struct NUM 21 { 22 int ord,v; 23 }a[MAXN],b[MAXN]; 24 25 int cmp(NUM a,NUM b) 26 {return a.v < b.v;} 27 28 inline int lowbit(int x) 29 {return x&(-x);} 30 31 inline void update(int x,int num) 32 { 33 while(x <= n) 34 { 35 c[x] += num; 36 x += lowbit(x); 37 } 38 } 39 40 inline int sum(int x) 41 { 42 int sum = 0; 43 while(x > 0) 44 { 45 sum += c[x]; 46 x -= lowbit(x); 47 } 48 return sum; 49 } 50 int main() 51 { 52 read(n); 53 for(register int i = 1;i <= n;++ i) 54 read(a[i].v),a[i].ord = i; 55 for(register int i = 1;i <= n;++ i) 56 read(b[i].v),b[i].ord = i; 57 std::sort(a+1,a+1+n,cmp); 58 std::sort(b+1,b+1+n,cmp); 59 for(register int i = 1;i <= n;++ i) 60 rank[a[i].ord] = b[i].ord; 61 for(register int i = 1;i <= n;++ i) 62 { 63 update(rank[i],1); 64 ans = (ans + i - sum(rank[i]))%MOD; 65 } 66 printf("%lld\n",ans); 67 return 0; 68 }
1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 #include<cstring> 5 6 const int MAXN = 100002; 7 const int MOD = 99999997; 8 inline void read(int &x) 9 { 10 char ch = getchar(),c = ch;x = 0; 11 while(ch < ‘0‘ || ch > ‘9‘) c = ch,ch = getchar(); 12 while(ch <= ‘9‘ && ch >= ‘0‘) x = (x<<1)+(x<<3)+ch-‘0‘,ch = getchar(); 13 if(c == ‘-‘) x = -x; 14 } 15 16 int n,c[MAXN],rank[MAXN]; 17 long long ans; 18 19 struct NUM 20 { 21 int val,ord; 22 }a[MAXN],b[MAXN]; 23 24 int cmp(NUM a,NUM b) 25 {return a.val < b.val;} 26 27 void merge(int l,int r) 28 { 29 if(l == r) return; 30 int mid = (l+r)>>1; 31 merge(l,mid); 32 merge(mid+1,r); 33 34 int tmp = l,i = l,j = mid+1; 35 for(;i<=mid && j<=r;) 36 { 37 if(rank[i] <= rank[j]) c[tmp++] = rank[i++]; 38 else if(rank[i] > rank[j]) c[tmp++] = rank[j++],ans += (mid-i+1); 39 } 40 ans %= MOD; 41 for(;i<=mid;) c[tmp++] = rank[i++]; 42 for(;j<=r;) c[tmp++] = rank[j++]; 43 44 for(int x = l;x <= r;++ x) 45 rank[x] = c[x]; 46 } 47 48 int main() 49 { 50 read(n); 51 for(int i = 1;i <= n;++ i) 52 read(a[i].val),a[i].ord = i; 53 for(int i = 1;i <= n;++ i) 54 read(b[i].val),b[i].ord = i; 55 std::sort(a+1,a+1+n,cmp); 56 std::sort(b+1,b+1+n,cmp); 57 for(int i = 1;i <= n;++ i) 58 rank[a[i].ord] = b[i].ord; 59 merge(1,n); 60 printf("%lld\n",ans); 61 return 0; 62 }
以上是关于洛谷 P1966 火柴排队 题解的主要内容,如果未能解决你的问题,请参考以下文章