您的位置:首页 > 其它

CodeVS3286 NOIP2013 火柴排队

2016-10-24 21:45 232 查看

题目

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 100010
using 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: