HDU 1394Minimum 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. 

InputThe 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. 
OutputFor 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个数的整数序列,每次可将序列首个数放到最后一位,其余数相对位置不变,通过这样的操作可以得到n种序列,要求这n种序列中倒置数的最小个数,即满足下标i<j,a[i]>a[j]。

其实说白了就是求不停倒置的最小逆序数

求逆序数用线段树或者树状数组都是挺方便的,每次加一个数进去,看此时后面的数有几个。

但这样肯定会超时,我们可以首先写出一开始的逆序数,发现每次倒置后,逆序数为减少a[i],而增加n-1-a[i]的。减少比它小的,增加比它大的

#include<bits/stdc++.h>
using namespace std;
const int maxn=5005;
int a[maxn<<4];
int add[maxn];
#define lson l,m,k<<1
#define rson m+1,r,k<<1|1
void hehe(int k)
{
    a[k]=a[k<<1]+a[k<<1|1];
}
void build(int l,int r,int k)
{
    a[k]=0;//先是假设这棵树都为0 
    if(l==r) return ;
    int m=(l+r)>>1;
    build(lson);
    build(rson);
}
int query(int x,int y,int l,int r,int k)
{
    if(x<=l&&r<=y)
    return a[k];
    
    int m=(l+r)>>1;
    int s=0;
    if(x<=m) s+=query(x,y,lson);
    if(y>m) s+=query(x,y,rson);
    return s;
}
void update(int p,int l,int r,int k)
{
    if(l==r)
    {
        a[k]++;//增加个数 
        return;
    }
    int m=(l+r)>>1;
    if(p<=m) update(p,lson);
    else update(p,rson);
    hehe(k);
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        build(0,n-1,1);
        int sum=0;//为一开始的逆序数 
        for(int i=0;i<n;i++)
        {
            scanf("%d",&add[i]);
            sum+=query(add[i],n-1,0,n-1,1);
            update(add[i],0,n-1,1);
        }
        int minn=sum;
        for(int i=0;i<n;i++)
        {
            sum+=n-add[i]-add[i]-1;
            minn=min(minn,sum);
        }
        cout<<minn<<endl;
    }
    return 0;
}

 

posted @ 2018-08-21 09:20  踩在浪花上  阅读(170)  评论(0编辑  收藏  举报