您的位置:首页 > 其它

Codevs3286 火柴排队

2015-10-25 20:51 477 查看
题目大意:给定两个长度为n的序列,序列中相邻的数可以相互交换。求至少交换多少次才能使火柴之间的距离和最小。

思路:可以用排序不等式证明,当每一根火柴与在各自排完序的序列中的序号相同者配对时,才有最小距离和。对于一个序列a,先确定其中元素相对于整个序列的位置,再用编号1、2、3进行定位,再对序列b中元素按已经在a中标好的标号与排名的对应关系对b进行标号,最后就是求逆序对个数了。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<cmath>
using namespace std;
const int maxn=100005;
const int mod=99999997;
int n;
int a[maxn],b[maxn];
int ranka[maxn],rankb[maxn];
map<int,int> has;
int id[maxn];
int tmpa[maxn],tmpb[maxn];
int ans=0,c[maxn];

void init()
{
scanf("%d",&n);
for (int i=1;i<=n;++i)
scanf("%d",&a[i]);
for (int i=1;i<=n;++i)
scanf("%d",&b[i]);
}

void getid()
{
memcpy(tmpa,a,sizeof(tmpa));
sort(tmpa+1,tmpa+n+1);
for (int i=1;i<=n;++i)
{
int pos=lower_bound(tmpa+1,tmpa+n+1,a[i])-tmpa;
ranka[i]=pos;
}
for (int i=1;i<=n;++i)
has[ranka[i]]=i;
memcpy(tmpb,b,sizeof(tmpb));
sort(tmpb+1,tmpb+n+1);
for (int i=1;i<=n;++i)
{
int pos=lower_bound(tmpb+1,tmpb+n+1,b[i])-tmpb;
rankb[i]=pos;
}
for (int i=1;i<=n;++i)
id[i]=has[rankb[i]];
}

void msort(int l,int r)
{
if (l==r)
return;
int mid=(l+r)/2;
msort(l,mid);
msort(mid+1,r);
int i=l,j=mid+1,k=l;
while (i<=mid && j<=r)
{
if (id[i]>id[j])
{
c[k]=id[j];
ans=(ans+(mid-i+1)%mod)%mod;
j++;
k++;
}
else
{
c[k]=id[i];
i++;
k++;
}
}
while (i<=mid)
{
c[k]=id[i];
i++;
k++;
}
while (j<=r)
{
c[k]=id[j];
j++;
k++;
}
for (i=l;i<=r;++i)
id[i]=c[i];
}

int main()
{
init();
getid();
msort(1,n);
printf("%d",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  归并排序 逆序对