您的位置:首页 > 其它

NOIP2013火柴排队

2017-10-26 19:26 232 查看
http://codevs.cn/problem/3286/

思路

首先易知,当a,b两串都进行过排序后,各对应位置的差值平方之和最小。

简单证明:

设序列只有两个数分别是a,b;c,d;且a < b;c < d

设S1=(a-c)^2+(b-d)^2,S2=(a-d)^2+(b-c)^2,

S1-S2=2ad+2bc-2ac-2bd=2a(d-c)+2b(c-d)=2(c-d)(b-a)<0

S1 < S2。

若存在a=b或c=d的情况S1仍为最小距离。

那么问题就转化成了,已知a串 b串对应位置,每次交换b中相邻的两个数,求最小的移动步数使b串各位置与a串一一对应。

交换过程类似于冒泡排序,我们知道冒泡排序每次交换都会使原串逆序对数减少1,则交换次数 = b串相对于a串的逆序对数(以a串对应b串位置的大小关系为比较标准)。统计逆序对数即可。

代码

//归并排序求逆序对——O(nlogn)AC
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int mod = 99999997;
int n,ans1,ans2;
int A[1000010],B[1000010],As[1000010],Bs[1000010],mp[1000010],pos[1000010],tmp[1000010];
void merge_sort(int l,int r)
{
if(l==r)
return;
int mid=(l+r)>>1;
merge_sort(l,mid);
merge_sort(mid+1,r);
int i=l;
int k=l;
int j=mid+1;
while(i<=mid&&j<=r)
{
if(pos[mp[B[i]]]>pos[mp[B[j]]])
{
tmp[k++]=B[j++];
ans2=((ans2%mod)+((mid-i+1)%mod))%mod;//在从i开始到mid中的所有数都会与j位置的数形成一个逆序对
}
else tmp[k++]=B[i++];
}
while(i<=mid)
tmp[k++]=B[i++];
while(j<=r)
tmp[k++]=B[j++];
for(int i=l;i<=r;i++)
B[i]=tmp[i];
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&A[i]);
As[i]=A[i];
pos[A[i]]=i;//按编号比较
}
for(int i=1;i<=n;i++)
{
scanf("%d",&B[i]);
Bs[i]=B[i];
}
sort(As+1,As+n+1);
sort(Bs+1,Bs+n+1);
for(int i=1;i<=n;i++)
{
ans1+=(As[i]-Bs[i])*(As[i]-Bs[i]);
mp[Bs[i]]=As[i];//最佳映射方案
}
merge_sort(1,n);
printf("%d",ans2);
return 0;
}


//冒泡排序求逆序对——O(n^2)会导致TLE
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int mod = 99999997;
int n,ans1,ans2;
int A[1000010],B[1000010],As[1000010],Bs[1000010],mp[1000010],pos[1000010];
bool flag;
void bubble_sort(int l,int r)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n-i;j++)
{
if(pos[mp[B[j]]]>pos[mp[B[j+1]]])
{
swap(B[j],B[j+1]);//每进行一次交换,逆序对的个数减少1
ans2++;
flag=1;
}
}
if(!flag)
break;
flag=0;
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&A[i]);
As[i]=A[i];
pos[A[i]]=i;//按编号比较
}
for(int i=1;i<=n;i++)
{
scanf("%d",&B[i]);
Bs[i]=B[i];
}
sort(As+1,As+n+1);
sort(Bs+1,Bs+n+1);
for(int i=1;i<=n;i++)
{
ans1+=(As[i]-Bs[i])*(As[i]-Bs[i]);
mp[Bs[i]]=As[i];//最佳映射方案
}
bubble_sort(1,n);
printf("%d",ans2);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息