题目:洛谷P1966、Vijos P1842、codevs3286。
题目大意:有两排火柴,每根都有一个高度。设a、b分别表示两排火柴的高度,现在要令$sum(a_i-b_i)^2$最小。现两排火柴已经排成一个序列,求最少交换多少次能满足条件。
解题思路:首先,只有当最大的对应最大的,次大的对应次大的,以此类推,得到的答案才可能最小。
然后我们发现,如此分析后,此题的答案与火柴实际长度无关,只要按照原来的大小顺序即可,且只需考虑对一排火柴进行交换即可。
因此我们对两组数据分别离散,然后通过第一组数据再对第二组数据再离散一遍即可。
最后其实就是求逆序对了,归并排序即可。
时间复杂度$O(nlog _2 n)$。
既然写了归并,还用什么sort(*^__^*)
C++ Code:
#include<cstdio> #include<cstring> using namespace std; int n,a[100005],ans,b[100005],c[100005],ys[100005],p[100005]; void merge(int* a,int l,int r){ int i=l,mid=l+r>>1,k=l; int j=mid+1; while(i<=mid&&j<=r){ if(a[i]>a[j]){ ans=(ans+mid-i+1)%99999997; c[k++]=a[j++]; } else c[k++]=a[i++]; } while(i<=mid)c[k++]=a[i++]; while(j<=r)c[k++]=a[j++]; for(i=l;i<=r;++i)a[i]=c[i]; } void mergesort(int* a,int l,int r){ if(l!=r){ int m=l+r>>1; mergesort(a,l,m); mergesort(a,m+1,r); merge(a,l,r); } } void merge_sort(int* a,int l,int r){ ans=0; mergesort(a,l,r); } int main(){ scanf("%d",&n); for(int i=1;i<=n;++i)scanf("%d",&a[i]); memcpy(p,a,sizeof p); merge_sort(p,1,n); for(int i=1;i<=n;++i) ys[p[i]]=i; for(int i=1;i<=n;++i)a[i]=ys[a[i]]; for(int i=1;i<=n;++i)scanf("%d",&b[i]); memcpy(p,b,sizeof p); merge_sort(p,1,n); for(int i=1;i<=n;++i) ys[p[i]]=i; for(int i=1;i<=n;++i)b[i]=ys[b[i]]; for(int i=1;i<=n;++i) ys[a[i]]=i; for(int i=1;i<=n;++i)b[i]=ys[b[i]]; merge_sort(b,1,n); printf("%d ",ans); return 0; }