hdu 1394 Minimum Inversion Number

题意:给出n个数,0<=k<=n-1,每次将第一个数放到最后,求最小的逆序数

分析:每次将开头的数num[i]放到最后,后面比num[i]小的数有num[i]个,所以减少num[i]个逆序数对,num[i[放到最后,前面比它大的数有n-1-num[i]个,所以每次操作后,当前的逆序数ans+n-2*num[i]-1,就是所要的结果。

可能有的人不能明白如何用线段树求开始的逆序数,这又一组测试数据,相信你按照我的程序走一圈,就能明白其中的过程

4

0 2 1 3

输出

1

代码

#include<stdio.h>
#define mid int m=(l+r)>>1
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

const int  maxn=5555;
int sum[maxn<<2];
int num[maxn];

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 ;
    mid;
    build(lson);
    build(rson);
}

void update(int p,int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt]++;
        return ;
    }
    mid;
    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];
    mid;
    int ans=0;
    if(L<=m)
        ans+=query(L,R,lson);
    if(R>m)
        ans+=query(L,R,rson);
    return ans;
}

int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        build(0,n-1,1);
        int ans=0;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&num[i]);
            ans+=query(num[i],n-1,0,n-1,1);
            update(num[i],0,n-1,1);
        }
        int t=ans;
        for(int i=0;i<n;i++)
        {
            t+=n-2*num[i]-1;
            if(ans>t)
                ans=t;
        }
        printf("%d
",ans);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/jihe/p/4776722.html