HDU 1394 Minimum Inversion Number

Description:

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的数列,可以变化为n个不同的数列(每次将首位元素放到最后一位),问这些序列中逆序数的个数最少为多少,逆序数:i < j and ai > aj,下标小于该元素的下标,值大于该元素。
 
可以先利用线段树求出本身的序列中有多少逆序数,然后判断每个元素放到最后一位时的逆序个数是否小于本身序列的逆序个数,逐次更新。
 
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

const int INF=0x3f3f3f3f;
const int N=5010;

struct node
{
    int left, right, num;
}no[4*N];
int Min;

void Bulid(int left, int right, int root)
{
    int mid;

    no[root].left = left;
    no[root].right = right;
    no[root].num = 0; 

    if (left == right) return ;

    mid = (left+right)/2;

    Bulid(left, mid, root*2);
    Bulid(mid+1, right, root*2+1);
}

void Insert(int p, int root) ///插入数据时就可以统计逆序数的个数
{
    int mid;

    no[root].num++;

    if (no[root].left == no[root].right) return ;

    mid = (no[root].left+no[root].right)/2;

    if (p <= mid)
    {
        Min += no[root*2+1].num;
        Insert(p, root*2);
    }
    else Insert(p, root*2+1);
}

int main ()
{
    int i, n, p[N], ans;

    while (scanf("%d", &n) != EOF)
    {
        Bulid(0, n-1, 1);
        Min = 0;

        for (i = 1; i <= n; i++)
        {
            scanf("%d", &p[i]);
            Insert(p[i], 1);
        }

        ans = Min;

        for (i = 1; i <= n; i++)
        {
            Min += (n-1-p[i]) - p[i]; ///首位移到最后一位时,逆序数加上那些比它大的数的个数,减去那些比它小的数的个数(因为该序列的元素都是0~n-1)
            ans = min(ans, Min);
        }

        printf("%d\n", ans);
    }

    return 0;
}
 
posted @ 2015-08-15 15:55  搁浅の记忆  阅读(135)  评论(0编辑  收藏  举报