HDU:1394 Minimum Inversion Number

来源:互联网 发布:剑三藏剑成女捏脸数据 编辑:程序博客网 时间:2024/06/09 14:40

用线段树求原始序列的逆序数,然后再递推求其它时候的逆序数,比较得最小值。

线段树求逆序数的原理跟树状数组一样,都是利用区间求和。我这里为了方便自己写的线段树,把下标调整成了从1开始到n

把当前第一个元素移动到末尾位置时,总逆序数的变化是:加上大于该数的个数,减去小于该数的个数。

 

#include <iostream>#include <cstdlib>#include <cstdio>#include <cstring>#include <cmath>#include <vector>#include <algorithm>#define MAXN 5005#define INF 2139062143#define ll  long longusing namespace std;const int MAX_N = 1<< 13;int sum[MAX_N];int mxn,n;void Init(){    mxn=1;    while(mxn<n) mxn*=2;    memset(sum,0,sizeof(sum));}void update(int k,int val){    k+=mxn-1;    sum[k]=val;    while(k/2>0)    {        k=k/2;        sum[k]+=val;    }}int query(int a,int b,int k,int l,int r){    if(r<a||b<l) return 0;    if(a<=l&&r<=b) return sum[k];    else    {        int v1=query(a,b,2*k,l,(l+r)/2);        int v2=query(a,b,2*k+1,(l+r)/2+1,r);        return v1+v2;    }}int main(){    while(scanf("%d",&n)!=EOF)    {        int arr[MAXN]= {0};        Init();        int sum=0;        for(int i=0; i<n; ++i)        {            scanf("%d",&arr[i]);            arr[i]++;            sum+=query(arr[i],n,1,1,mxn);            update(arr[i],1);        }        int ans=sum;        for(int i=0; i<n; ++i)        {            sum=sum+(n-arr[i])-(arr[i]-1);            ans=min(sum,ans);        }        printf("%d\n",ans);    }    return 0;}


 

0 0
原创粉丝点击