【HDU1394】Minimum Inversion Number

来源:互联网 发布:js移除最后一个子元素 编辑:程序博客网 时间:2024/06/07 09:06

题意:
给出一个由0到n-1组成的序列,每次把队首的元素移到队尾,求形成的n个序列中逆序对数目的最小值(n<=5000)
题解:
首先可以对初始数组求一次逆序对(O(nlogn))
很自然的想到,如果每次变幻数组后再求逆序对(O(n²logn)),显然会爆
但我们可以做到O(1)的递推
假设原始数组的逆序对个数是sum个,如果把x[1]放到x[n]后面,逆序列个数会减少x[1]个,相应会增加n-(x[1]+1)个
即有
sum+=(n-(x[i]+1))-(x[i]);
意识到这个就很好做了

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define getmid int m=(l+r)>>1const int maxn=5555;int sum[maxn<<2];void Pushup(int rt){    sum[rt]=sum[rt<<1]+sum[rt<<1|1];}void Build(int l,int r,int rt){    sum[rt]=0;    if(l==r) return;    getmid;    Build(lson);    Build(rson);}void Update(int p,int l,int r,int rt){    if(l==r)    {        sum[rt]++;return;    }    getmid;    if(p<=m) Update(p,lson);    else  Update(p,rson);    Pushup(rt);}int Query(int L,int R,int l,int r,int rt){    if(L<=l&&R>=r) return sum[rt];    getmid;    int ret=0;    if(L<=m) ret+=Query(L,R,lson);    if(R>m)  ret+=Query(L,R,rson);    return ret;}int x[maxn];int main(){    int n;    while(~scanf("%d",&n))    {        Build(0,n-1,1);        int sum=0;        for(int i=0;i<n;i++)        {            scanf("%d",&x[i]);            sum+=Query(x[i],n-1,0,n-1,1);            Update(x[i],0,n-1,1);        }        int ret=sum;        for(int i=0;i<n;i++)        {            sum+=n-x[i]-1-x[i];            ret=min(ret,sum);        }        printf("%d\n",ret);    }    return 0;}