code3286 火柴排队

这道题目相当于是让我们把a,b对齐,即a中第i大的数与b中第i大的数下标相同
一看到交换次数,很容易让人想到归并排序
我的做法是这样的
就样例而言:
a:1 3 4 2
b:1 7 2 4
读进来之后先处理a,b 把a,b按大小离散成1..n
离散之后
a:1 3 4 2
b:1 4 2 3
那么我们现在的问题就变成了,求a转化为b所用的次数
但是仍然很麻烦,所以要进一步离散 - -!
我们不难看出,在a数组中,1的目的地是1。2的目的地是3。3的目的地是4.4的目的地是2 那么我们可以另开一个数组,p[i]记录a[i]的目的地,即p={1,4,2,3}
当a的元素全都到达目的地之后,p数组就是{1,2,3,4}
所以答案就是使P数组变成1..n所需要的移动次数,也就是p的逆序对个数

如何求逆序对? http://www.cnblogs.com/FuTaimeng/p/5652994.html

代码:

#include<iostream>
#include<algorithm>
#define Size 100005 
using namespace std;

int n;
int a[Size],b[Size];
struct T{
    int num,p;
}temp[Size];
int f[Size],place[Size];
int cc[Size];
int ans=0;

bool ff(T x,T y){return x.num<y.num;}
void lisan(T x[],int y[]){
    sort(x+1,x+1+n,ff);
    for(int i=1;i<=n;i++){
        y[x[i].p]=i;
    }
}

void he(int st,int end,int mid){
    int l=st,r=mid+1;
    for(int i=st;i<=end;i++){
        if(l<=mid&&(r>end||f[l]<=f[r])){
            cc[i]=f[l]; l++;
        }
        else{
            cc[i]=f[r]; r++;
            ans+=mid-l+1;
            ans%=99999997;
        }
    }
    for(int i=st;i<=end;i++)f[i]=cc[i];
}
void my_msort(int l,int r){
    if(l<r){
        int mid=(l+r)/2;
        my_msort(l,mid);
        my_msort(mid+1,r);
        he(l,r,mid);
    }
}

int main(){
    cin>>n;    
    for(int i=1;i<=n;i++)cin>>temp[i].num,temp[i].p=i;
    lisan(temp,a);
    for(int i=1;i<=n;i++)cin>>temp[i].num,temp[i].p=i;
    lisan(temp,b);
    
    for(int i=1;i<=n;i++)place[b[i]]=i;
    for(int i=1;i<=n;i++){
        f[i]=place[a[i]];
    }
    my_msort(1,n);
    cout<<ans<<endl; 
}

 

posted @ 2016-07-08 12:13  FuTaimeng  阅读(144)  评论(0编辑  收藏  举报