hash一下 + 归并排序计算逆序对数

来源:互联网 发布:mac gdb 动态调试程序 编辑:程序博客网 时间:2024/05/16 13:39

OJ题目:click here~~

题目分析:给一个序列,选择两个数,交换这两个数的位置,使得交换后,序列的逆序数最少。给出交换后的逆序数。

先将序列中的数hash一下,是为了下面方便计算数的次数。

归并排序,求逆序数。

枚举所有可选的两个数a , b,计算这两个数之间,比a大的数,比a小的数,比b大的数,比b小的数。交换a , b 之后 ,逆序数 = 原来的逆序数 + 比a大的数 + 比b小的数 - 比a小的数 - 比b大的数 + a,b逆序数的变化。

AC_CODE

const int Max_N = 1002;int x[Max_N] , h[Max_N] , sum ;int dpless[Max_N][Max_N] ;//dp[i][j];到i处为止,比j小的数的个数int dpbig[Max_N][Max_N] ;//dpbig[i][j]:到i处为止,比j大的数的个数void Merg(int L , int R){    if(L == R) return ;    int M = (L + R)>>1;    Merg(L , M);    Merg(M + 1 , R);    for(int i = M + 1;i <= R;i++){        sum += (x + 1 + M) - upper_bound(x + L , x + 1 + M , x[i]);    }    sort(x + L , x + R + 1);}int main(){    int i , j , k , n;    while(scanf("%d",&n) != EOF){        for(i = 1;i <= n;i++){            scanf("%d",&x[i]);            h[i] = x[i];        }        //先hash一下        sort(x + 1 , x + 1 + n);//需要先排序        int len = unique(x + 1, x + 1 + n) - (x + 1);//不同的元素的个数        for(i = 1;i <= n;i++)            h[i] = lower_bound(x + 1 , x + 1 + len , h[i]) - x;        for(i = 1;i <= n;i++) x[i] = h[i];        sum = 0 ;        Merg(1 , n) ;//求原来序列的逆序数        if(!sum){            puts("0") ;            continue;        }        memset(dpless , 0 , sizeof(dpless));        memset(dpbig , 0 , sizeof(dpbig));        for(i = 1;i <= n;i++) x[i] = h[i];        for(i = 1;i <= n;i++){            for(j = 1;j <= len;j++)                dpless[i][j] = dpless[i - 1][j];            for(j = x[i] + 1;j <= len;j++)                dpless[i][j]++;            for(j = 1;j <= len;j++)                dpbig[i][j] = dpbig[i - 1][j];            for(j = 1;j < x[i];j++)                dpbig[i][j]++;        }        int ans = sum;        int a , b , aless , bless , abig , bbig ;        for(i = 1;i <= n;i++){            for(j = i + 1;j <= n;j++){                a = x[i];                b = x[j];                bless = dpless[j - 1][b] - dpless[i][b];                bbig = dpbig[j - 1][b] - dpbig[i][b];                abig = dpbig[j - 1][a] - dpbig[i][a];                aless = dpless[j - 1][a] - dpless[i][a];                int k = 0 ;                if(a < b) k = 1;                if(b < a) k = -1;                ans = min(ans , sum + bless + abig - aless - bbig + k);            }        }        cout << ans << endl;    }}


0 0