HDU 1394 - Minimum Inversion Number(BIT)

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

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

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

posted @ 2018-09-20 11:16  不想吃WA的咸鱼  阅读(73)  评论(0编辑  收藏  举报