HDU 1394 - Minimum Inversion Number(BIT)

题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=1394

【题意】
已知一个数列 A A ,数列长度 < = 5000 n<=5000 A i A_i 范围在 [ 0 , n 1 ] [0,n-1] ,并且不重复,也就是说 A A 是一个 [ 0 , n 1 ] [0,n-1] 的排列。每次可以将数列的第一个数移动到最后面,这样可以构造出 个数列。求这 个数列中的最小逆序数。

【思路】
只需要求出初始序列的逆序对个数,剩下的 n 1 n-1 个序列的逆序对个数可以递推出来,假设现在数列的第一个数是 x x ,那么后面有 x x 个元素 [ 0 , x 1 ] [0,x-1] x x 小,剩下 n 1 x n-1-x 个元素比 x x 大,这样原来会有 x x 个逆序对产生,如果把 x x 移动到数列最后,那么原来的 x x 个逆序对会消失,新产生 n 1 x n-1-x 个逆序对,所以每次移动一个元素 x x 时,会额外产生 n 1 2 x n-1-2x 个逆序对

#include<bits/stdc++.h>
using namespace std;

const int maxn=5005;

int n;
int a[maxn];
int bit[maxn];

void add(int i,int x){
    while(i<=n){
        bit[i]+=x;
        i+=i&-i;
    }
}

int sum(int i){
    int ans=0;
    while(i){
        ans+=bit[i];
        i-=i&-i;
    }
    return ans;
}

int main(){
    while(scanf("%d",&n)==1 && n){
        for(int i=0;i<n;++i) scanf("%d",&a[i]);
        memset(bit,0,sizeof(bit));
        int inv=0;
        for(int i=0;i<n;++i){
            inv+=sum(n)-sum(a[i]+1);
            add(a[i]+1,1);
        }
        int ans=inv;
        for(int i=0;i<n-1;++i){
            inv+=n-1-a[i]*2;
            ans=min(ans,inv);
        }
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xiao_k666/article/details/82783721