John’s Inversions 2011-2012 ACM-ICPC, NEERC, Northern Subregional Contest

题意是给N张牌  每张牌上有两个不同颜色的数字 (有序)  求一种排列方式使同种颜色的数的逆序数对最少。

思路:

假设 对 逆序数对较多的颜色的牌排序,使得一种颜色的牌的逆序数达到最小,另一种颜色的数字会存在一些逆序数对。不存在更优的移动方式,使得另一种颜色减少的逆序数对大于已经有序的颜色增加的逆序数对。

实现:

用归并排序求逆序数对。

 AC代码:

#include <bits/stdc++.h>
using namespace std;
struct node{
    int red,blue;
}card[100005];
bool cmp1(node n1,node n2) {
    if (n1.red==n2.red) return n1.blue<n2.blue;
    else return n1.red<n2.red;
}
bool cmp2(node n1,node n2) {
    if (n1.blue==n2.blue) return n1.red<n2.red;
    else return n1.blue<n2.blue;
}
long long cnt1=0,cnt2=0;
int A[100005],T[100005];
void merge_sort(int x,int y) {
    if (y-x>1) {
        int m=x+(y-x)/2;
        int p=x,q=m,i=x;
        merge_sort(x,m);
        merge_sort(m,y);
        while (p<m||q<y){
            if (q>=y||(p<m&&A[p]<=A[q])) T[i++]=A[p++];
            else {
                T[i++]=A[q++];
                cnt1+=(m-p);
            }
        }
        for (i=x;i<y;++i) A[i]=T[i];
    }
}
void merge_sort2(int x,int y) {
    if (y-x>1) {
        int m=x+(y-x)/2;
        int p=x,q=m,i=x;
        merge_sort2(x,m);
        merge_sort2(m,y);
        while (p<m||q<y){
            if (q>=y||(p<m&&A[p]<=A[q])) T[i++]=A[p++];
            else {
                T[i++]=A[q++];
                cnt2+=(m-p);
            }
        }
        for (i=x;i<y;++i) A[i]=T[i];
    }
}

int main() {
    //freopen("datain","r",stdin);
    freopen("john.in","r",stdin);
    freopen("john.out","w",stdout);
    int n;
    cin>>n;
    for (int i=0;i<n;++i) scanf("%d %d",&card[i].red,&card[i].blue);
    //first
    sort(card,card+n,cmp1);
    for (int i=0;i<n;++i) A[i]=card[i].blue;
    //for (int i=0;i<n;++i) cout<<A[i]<<" ";
    merge_sort(0,n);
    //cout<<cnt1<<endl;
    //second
    sort(card,card+n,cmp2);
    for (int i=0;i<n;++i) A[i]=card[i].red;
    //for (int i=0;i<n;++i) cout<<A[i]<<" ";
    merge_sort2(0,n);
    //cout<<cnt2<<endl;
    //for (int i=0;i<n;++i) cout<<A[i]<<" ";
    cout<<min(cnt1,cnt2)<<endl;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值