HDU1394 Minimum Inversion Number

来源:互联网 发布:雷神笔记本怎么样知乎 编辑:程序博客网 时间:2024/06/11 16:42

HDU1394 Minimum Inversion Number

标签:线段树,树状数组

http://www.sakurasake.icoc.me/nd.jsp?id=7#_np=2_327

Time Limit: 2000/1000 MS(Java/Others)    Memory Limit: 65536/32768 K (Java/Others)

Problem Description

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

For a given sequence of numbers a1, a2, ..., an, if we move the first m >= 0numbers to the end of the seqence, we will obtain another sequence. There aretotally 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 ofthe above sequences.

 

 

Input

The input consists of a number of testcases. Each case consists of two lines: the first line contains a positiveinteger n (n <= 5000); the next line contains a permutation of the nintegers from 0 to n-1.

 

 

Output

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

 

 

Sample Input

10

1 3 6 9 0 8 5 7 4 2

 

 

Sample Output

16

 

 

Author

CHEN, Gaoli

 

 

Source

ZOJMonthly, January 2003

 

分析:快速求逆序数,暴力算法主要分为两步:穷举逆序数,通过公式推出结果

公式为sum=sum-a[i]+(n-a[i]-1)

第二步几乎不可能优化,所以可以使用线段树优化第一步,时间复杂度为O(n log n)

当然通过树状数组应该也可以,就没有写代码了2333

举个栗子

序列3,2,5,4,0,1

3之前没有数大于它本身,val[1]=0

2之前有3大于它,val[2]=1

5之前没有数大于它本身,val[3]=0

4之前有5大于它,val[4]=1

0之前有3,2,5,4,大于它,val[5]=4

1之前有3,2,5,4大于它,val[6]=5

所以实际上,每插入val[i],就查询在[val[i],n-1]之间的数的个数,依次累加即可

#include<iostream>#include<iomanip>#include<cmath>#include<cstring>#include<ctime>#include<cstdio>#include<cstdlib>#include<algorithm>#include<vector>#include<queue>#include<stack>#define LL(x) ((x)<<1)#define RR(x) ((x)<<1|1)inline int read(){    int f=1,x=0;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}using namespace std;struct Seg_Tree{    int left,right,val;    int calmid()    {        return (left+right)/2;    }}tt[15000];int val[5001];void make(int left,int right,int idx){    tt[idx].left=left;    tt[idx].right=right;    tt[idx].val=0;    if(left==right)return;    int mid=tt[idx].calmid();    make(left,mid,LL(idx));    make(mid+1,right,RR(idx));}int query(int left,int right,int idx){    if(left==tt[idx].left&&right==tt[idx].right) return tt[idx].val;    int mid=tt[idx].calmid();    if(right<=mid)return query(left,right,LL(idx));    else if(mid<left)return query(left,right,RR(idx));    else return query(left,mid,LL(idx))+query(mid+1,right,RR(idx));}void change(int id,int idx){    tt[idx].val++;    if(tt[idx].left==tt[idx].right)return;    int mid=tt[idx].calmid();    if(id<=mid)        change(id,LL(idx));    else change(id,RR(idx));}int main(){    int i,n,sum;    while(scanf("%d",&n)==1)    {        make(0,n-1,1);        for(i=0;i<n;i++)sum=0;        for(i=0;i<n;i++)        {            scanf("%d",&val[i]);            sum+=query(val[i],n-1,1);            change(val[i],1);        }        int ret=sum;        for(i=0;i<n;i++)        {            sum=sum-val[i]+(n-val[i]-1);            ret=min(ret,sum);        }        printf("%d\n",ret);    }    return 0;}


原创粉丝点击