Codevs3286 火柴排隊
阿新 • • 發佈:2019-02-05
題目大意:給定兩個長度為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;
}