NOIP2013提高组day1 第二题
思路
其中 Σ(ai-bi)^2=Σ(ai^1+bi^2-2aibi)差值最小的意思就是Σaibi最大,即顺序和最大
可先把两盒火柴分别排序,然后用一个数组把一盒火柴的编号保存为相对应的另一盒火柴的下标,再对该数组归并求逆序对
最小交换次数即求逆序对,也可用归并或树状数组来求
以下是归并的代码O(3logn)
#include<cstdio>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int maxx=100001;
int n,ys=99999997;
LL ans;
struct xx{
int x,num;
}a[maxx],b[maxx];
int c[maxx],d[maxx];
bool cmp(const xx a,const xx b)
{
return a.x<b.x;
}
void merge(int l,int r)
{
if(l==r)return;
int mid=(l+r)>>1;
merge(l,mid);
merge(mid+1,r);
int i=l,j=mid+1,k=l;
while(i<=mid&&j<=r)
{
if(c[i]>c[j]){ //逆序对只算向左移的数字
ans=(ans+mid-i+1)%ys;
d[k++]=c[j++];
}
else d[k++]=c[i++];
}
while(i<=mid)d[k++]=c[i++];
while(j<=r) d[k++]=c[j++];
for(int i=l;i<=r;i++)
c[i]=d[i];
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
scanf("%d",&a[i].x),a[i].num=i;
for(int i=1;i<=n;i++)
scanf("%d",&b[i].x),b[i].num=i;
sort(a+1,a+n+1,cmp);
sort(b+1,b+n+1,cmp);
for(int i=1;i<=n;i++) c[a[i].num]=b[i].num;
merge(1,n);
cout<<ans%ys;
return 0;
}