您的位置:首页 > 其它

HDU:1394 Minimum Inversion Number

2014-01-26 23:50 253 查看
用线段树求原始序列的逆序数,然后再递推求其它时候的逆序数,比较得最小值。

线段树求逆序数的原理跟树状数组一样,都是利用区间求和。我这里为了方便自己写的线段树,把下标调整成了从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 long
using 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: