【NOIP2013提高组 day1】火柴排队
题解
因为化简式子可得是求Σ(ai2-2*ai*bi+bi2)i⊂(1,n)
再次化简可得Σai2+Σbi2-2*Σai*bi
显然前两项是定值,所以只需要考虑最后一项;
经过简单的数学计算就可以知道当a与b最接近时最大此时和最小;
就可以知道目标状态时大对大,小对小。还可以发现移动任意一个数组都可以等价于转变另一个数组,所以可以把一个看作不动,让另一个去匹配;中途还需要优化一些;因为题目要求的是交换次数,就可以发现交换的条件就是不满足升序时,那就是求逆序对,大家就可以很轻易地想到用树状数组或归并排序求逆序对;
#include<bits/stdc++.h>
using namespace std;
struct n{
int num,ord;
}first[100010],second[100010];
int a[100010],b[100010],ans;
int compare(n x,n y){
return x.num<y.num;
}
void Merge(int l,int r){
if(l>=r) return ;
int mid=(l+r)/2;
Merge(l,mid);
Merge(mid+1,r);
int i=l,j=mid+1,k=l;
while(i<=mid&&j<=r){
if(a[i]>a[j]){
b[k++]=a[j++];
ans+=mid-i+1;
ans%=99999997;
}
else b[k++]=a[i++];
}
while(i<=mid) b[k++]=a[i++];
while(j<=r) b[k++]=a[j++];
for(int i=l;i<=r;i++)
a[i]=b[i];
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&first[i].num);
first[i].ord=i;
}
for(int i=1;i<=n;i++)
{
scanf("%d",&second[i].num);
second[i].ord=i;
}
sort(first+1,first+n+1,compare);
sort(second+1,second+n+1,compare);
for(int i=1;i<=n;i++)
a[first[i].ord]=second[i].ord;
Merge(1,n);
printf("%d",ans);
return 0;
}