CodeVS3286 NOIP2013 火柴排队

来源:互联网 发布:学生管理系统java界面 编辑:程序博客网 时间:2024/05/21 10:01

题目

http://codevs.cn/problem/3286/

题解

  思想性较强的一道题。
  显然,最终排成这样一定能让距离和最小:假如a[i]在整个a序列中排行第k大,那么b[i]在整个序列b中排行也是第k大。
  假设已经排成上述情形,你会发现不管你怎样交换,都一定会使距离和增大。
  于是我们将a序列离散,把原来a里的元素修改为它是第几大,b数组做同样的操作。因为题目说同一序列元素互异,所以a和b中的元素都是1到N。
  那么问题就变成,每次只允许交换相邻元素,最少交换几次能是b序列变成a序列。
  我们可以把a[i]与i一一映射,那么table[a[i]]=i表示a[i]这个数应该在第i个位置。
  那么将b[i]赋值成table[b[i]],表示这个元素排序后应该最终在第几位。
  归并求逆序对就好了。

代码

//归并求逆序对 #include <cstdio>#include <algorithm>#include <map>#define maxn 100010using namespace std;int a1[maxn], a2[maxn], b[maxn], c[maxn], N;long long cnt;map<int,int> table;void pai(const int l, const int r, int *a){if(l==r)return;int i, j, mid=l+r>>1, p;pai(l,mid,a),pai(mid+1,r,a);for(i=l;i<=mid;i++)b[i]=a[i];for(i=mid+1;i<=r;i++)c[i]=a[i];for(i=l,j=mid+1,p=l;p<=r;p++){if(b[i]<=c[j] and i<=mid or j>r)a[p]=b[i++];else a[p]=c[j++],cnt+=mid-i+1;}}void lisan(int* a){int i;table.clear();for(i=1;i<=N;i++)b[i]=a[i];sort(b+1,b+N+1);for(i=1;i<=N;i++)table[b[i]]=i;for(i=1;i<=N;i++)a[i]=table[a[i]];}int main(){int i;scanf("%d",&N);for(i=1;i<=N;i++)scanf("%d",a1+i);for(i=1;i<=N;i++)scanf("%d",a2+i);lisan(a1),lisan(a2);table.clear();for(i=1;i<=N;i++)table[a1[i]]=i;for(i=1;i<=N;i++)a2[i]=table[a2[i]];pai(1,N,a2);printf("%d\n",cnt%99999997);return 0;}


0 0
原创粉丝点击