1. 程式人生 > >Codevs3286 火柴排隊

Codevs3286 火柴排隊

  • 題目大意:給定兩個長度為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; }