Fork me on github

hdu 1394 Minimum Inversion Number (树状数组求逆序对)

The inversion number of a given number sequence a1, a2, ..., an is the number of pairs (ai, aj) that satisfy i < j and ai > aj. 

 

For a given sequence of numbers a1, a2, ..., an, if we move the first m >= 0 numbers to the end of the seqence, we will obtain another sequence. There are totally n such sequences as the following: 

 

a1, a2, ..., an-1, an (where m = 0 - the initial seqence) 

a2, a3, ..., an, a1 (where m = 1) 

a3, a4, ..., an, a1, a2 (where m = 2) 

... 

an, a1, a2, ..., an-1 (where m = n-1) 

 

You are asked to write a program to find the minimum inversion number out of the above sequences. 

Input

The input consists of a number of test cases. Each case consists of two lines: the first line contains a positive integer n (n <= 5000); the next line contains a permutation of the n integers from 0 to n-1. 

Output

For each case, output the minimum inversion number on a single line. 

Sample Input

10

1 3 6 9 0 8 5 7 4 2

Sample Output

16

 

题目大意:

给定一个长为n的序列。求1..n,2..n..1,3..n..12,4..n..1..3,...这n种排列最小的逆序数。

 

1、树状数组

写这道题更多地是给自己一个树状数组的模板。建立在sum数组上的lowbit,add,getsum三个操作。

2、求逆序数

在初始全为0的长为n的数组上的操作。结构体排序。若有重复的值,注意排序的比较方式,应当是序号较大的排在后面,避免被记入逆序数。

3、本题技巧

0..n-1这n个数的序列。若第一个数为a,将其放至最后一位,则逆序数减少a,增加n-1-a,从而看做增加n-1-2a。

 

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int maxn=5000;
const int inf=1000000000;

int a[maxn+10];

struct tnode
{
    int num;
    int seq;
    bool operator<(const tnode& y) const
    {
        return num<y.num;
    }
};
tnode node[maxn+10];

int sum[maxn+10];

inline int lowbit(int x)
{
    return x&-x;
}

inline void add(int x,int val,int n)//向1..n序列的x位置加上val
{
    for(int i=x;i<=n;i+=lowbit(i))
        sum[i]+=val;
}

inline int getsum(int x)//1..x的和
{
    int ret=0;
    for(int i=x;i;i-=lowbit(i))
        ret+=sum[i];
    return ret;
}

int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1;i<=n;i++)
            scanf("%d",a+i);
        for(int i=1;i<=n;i++)
            node[i]=(tnode){a[i],i};
        sort(node+1,node+n+1);
        int ans0=0;
        memset(sum,0,sizeof(sum));
        for(int i=n;i>=1;i--)
        {
            ans0+=getsum(node[i].seq);
            add(node[i].seq,1,n);
        }
        int ans=ans0;
        for(int i=1;i<n;i++)
        {
            ans0=ans0+n-1-2*a[i];//0..n-1的排列逆序数规律
            ans=min(ans,ans0);
        }
        printf("%d\n",ans);
    }
    return 0;
}
View Code

 

posted @ 2018-10-05 20:40  acboyty  阅读(137)  评论(0编辑  收藏  举报