题意:题目给出两个等长的序列,求交换两个序列的最小次数,使两个序列之间的值满足 sum(ai-bi)^2 最小;
解法:归并排序/树状数组+求逆序对
1.归并排序/树状数组:这两种方式都是可以较快地求出逆序对个数
2.求逆序对:因为只有当两个序列相对的数值都是其本序列中的相同等级的数,才能使等式最小。而移动两个序列的同一个数相当于没有移动,故题目可转化为将一个序列转变成为另一个序列的最小移动次数。此时不难看出 a序列转变为 b序列的最小移动次数就是 a的逆序对个数;
下面给出树状数组求逆序对的代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cstdlib>
#include<ctime>
#define ll long long
using namespace std;
const int N = 100086;
const int mod = 99999997;
int n;
struct node{
int sum,idx;
}a[N],b[N],c[N];
ll ans=0,d[N];
int lowbit(int x){
return x&-x;
}
void add(int x,int k){
while(x<=n){
d[x]+=k;
d[x]%=mod;
x+=lowbit(x);
}
}
int query(int x){
int rel=0;
while(x){
rel+=d[x];
x-=lowbit(x);
}
return rel;
}
bool cmp(node x,node y){
return x.sum<y.sum;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i].sum),a[i].idx=i;
for(int i=1;i<=n;i++) scanf("%d",&b[i].sum),b[i].idx=i;
sort(a+1,a+1+n,cmp);
sort(b+1,b+1+n,cmp);
for(int i=1;i<=n;i++) c[i].sum=a[i].idx,c[i].idx=b[i].idx;
sort(c+1,c+1+n,cmp);
for(int i=1;i<=n;i++){
add(c[i].idx,1);
ans+=i-query(c[i].idx);
ans%=mod;
}
printf("%lld",ans%mod);
return 0;
}