hdu 1394 Minimum Inversion Number

题意:   输入0 ~ n-1 总共n个数,每次取最前面的一个数放到序列最后面形成新的序列,问这些序列中逆序对数目最少的是多少。

如: 输入0,3,2,4,1,5

先求逆序对数目,第一次将0放到最后 3,2,4,1,5,0      再求逆序对数目,依次下去,取逆序对数目最小值。

 

用线段树求最初输入的序列的逆序对。

求逆序对有两种思想,一是:求a[i]后面比它小的数的个数,累加。二是:求a[i]前面比它大的数的个数,累加。线段树用的是第二种思想

每次将a[i]插入,就将区间为[i,i]的叶子结点值置1.

如我们求[a[i], n-1]区间内的1的个数,就是求a[i]前面比a[i]大的数的个数,因为比a[i]大的数已经插入并且在[a[i], n-1]内。

 

每次移动最前面的数到最后面,逆序对数目变化是 - a[i] + (n - 1) - a[i]

因为a[i]后面有a[i]个比它小的数,有(n - 1) - a[i]个比它大的数,所以每次移动,逆序对减少a[i] ,增加(n - 1) - a[i].

 

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<algorithm>
using namespace std;

const int INF = 0x3f3f3f3f;
const int MAXN = 5050;
int num[MAXN << 2];

void PushUp(int rt)
{
    num[rt] = num[rt << 1] + num[rt << 1 | 1];
}

void build(int l, int r , int rt)
{
    if(l == r)
    {
        num[rt] = 0;                 //建树叶子结点值置0
        return;
    }
    int mid = ( l + r) >> 1;
    build( l, mid, rt << 1);
    build(mid + 1, r, (rt << 1) +1 );
    PushUp(rt);
}

void update(int p, int l, int r, int rt)
{
    if(l == r)
    {
        num[rt] ++;                   //插入一个数,将其对应的叶子结点值置1
        return;
    }
    int mid = ( l + r ) >> 1;
    if(p <= mid)
        update(p, l, mid, rt << 1);
    else
        update(p, mid + 1, r, (rt << 1) + 1);
    PushUp(rt);
}

int query(int ll,int rr,int l,int r,int rt)
{
    if(ll <= l && r <= rr)
    {
        return num[rt];
    }
    int mid = (l+r) >> 1;
    int res = 0;
    if(ll <= mid)
        res += query(ll,rr,l,mid,rt << 1);
    if(rr > mid)
        res += query(ll,rr,mid+1,r,(rt << 1)+1);
    return res;
}

int main()
{
    int n;
    int a[MAXN];
    while(~scanf("%d",&n))
    {
        build(0,n-1,1);
        int res = 0;
        for(int i = 0; i< n; i++)
        {
            scanf("%d",&a[i]);
            res += query(a[i],n-1,0,n-1,1);         //求(a[i],n-1)区间内1的个数
            update(a[i],0,n-1,1);                    
        }
        int ans = INF;
        for(int i = 0; i < n; i++)
        {
            res = res -a[i] + n - 1 - a[i];         //没次移动,次序对数目变化
            ans = ans < res ? ans : res;
        }
        printf("%d\n",ans);
    }
}

 

posted @ 2015-07-18 16:25  杨永华  阅读(90)  评论(0编辑  收藏  举报