【NOIP2013提高组 day1】火柴排队

【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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值