HDOJ 1394 Minimum Inversion Number

【题目描述】

给定一个序列a1...an,每次可以吧第一个元素放到最后形成一个新的序列,求解这n个序列中逆序数最小的一个。

【思路】

线段树的应用——利用线段树求解逆序数。

一组逆序对ai,aj满足ai>aj&&i<j,求解时先进行排序,找出没个数的相对大小。

插入的时候从最后一个开始向前一次插入,每次将x[i]插入到k时。询问1...k这段中已插入的个数。

因为1...k这段中已插入的个数即为排在x[i]之后并且比x[i]小的数的个数,即为包含x[i]的逆序对总数。

求出原序列的逆序对数之后,每次变更之后的逆序数可以提出来。

#include<cstdio>
#include<algorithm>
#define lson n<<1
#define rson n<<1|1
#define N 50100
using namespace std;
struct{
    int l,r,cnt;
}s[N<<2];
int x[N];
void build(int l,int r,int n){
    s[n].l=l;
    s[n].r=r;
    s[n].cnt=0;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(l,mid,lson);
    build(mid+1,r,rson);
}
void update(int n,int k){
    s[n].cnt++;
    if(s[n].l==s[n].r)
    return;
    int mid=(s[n].l+s[n].r)>>1;
    if(k<=mid)
    update(lson,k);
    else
    update(rson,k);
}
int query(int l,int r,int n){
    if(s[n].l==l&&r==s[n].r)
    return s[n].cnt;
    int mid=(s[n].l+s[n].r)>>1;
    if(r<=mid)
    return query(l,r,lson);
    else if(l>mid)
    return query(l,r,rson);
    else
    return query(l,mid,lson)+query(mid+1,r,rson);
}
int main(){
    int n;
    while(~scanf("%d",&n)){
        int ans=0;
        build(1,n,1);
        for(int i=1;i<=n;i++)
            scanf("%d",&x[i]);
        for(int i=n;i>0;i--){
            ans+=query(1,x[i]+1,1);
            update(1,x[i]+1);
        }
        
        int min=ans;
        for(int i=1;i<=n;i++){
            ans=ans+n-2*x[i]-1;
            min=min<ans?min:ans;
        }
        printf("%d\n",min);
    }
    return 0;
}

 

 

posted @ 2012-07-03 23:25  silver__bullet  阅读(121)  评论(0编辑  收藏  举报