天天看點

Minimum Inversion Number 樹狀數組Minimum Inversion Number

Minimum Inversion Number

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

Total Submission(s): 21360    Accepted Submission(s): 12802

Problem 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
        

Author CHEN, Gaoli  

Source ZOJ Monthly, January 2003  

Recommend Ignatius.L

題目的意思是給你一個n,然後是一段包含0~n-1全部數字的序列,然後有一個操作把前面的數放到後面來,這樣的操作可以形成n個序列,讓你求出這樣所有的逆序序列裡最小的逆序數 樹狀數組實作求取逆序數:把樹狀數組當做标記數組使用,從後往前輸入每一個資料計算出現了多少個比這個數小的數的個數因為樹狀數組可以快速求和,這樣就可以在nlogn的時間複雜度内求得逆序數了 然後就是怎麼根據第一個求得的下一個狀态的逆序數了 對于開頭的第一個數,如果這個數放在後面,首先逆序數會減少【後面有多少個比他小的數的個數】,加到後面會導緻逆序數增加【前面有多少個比他大的】,由于這裡包含了所有的0~n-1的數,是以很容易求得所有的逆序數。

#include<stdio.h>

#include<string.h>

#include<algorithm>

using namespace std;

const int MAXN=5050;

int c[MAXN];

int n;

int lowbit(int x)

{

    return x&(-x);

}

void add(int i,int val)

{

    while(i<=n)

    {

        c[i]+=val;

        i+=lowbit(i);

    }

}

int sum(int i)

{

    int s=0;

    while(i>0)

    {

        s+=c[i];

        i-=lowbit(i);

    }

    return s;

}

int a[MAXN];

int main()

{

    while(scanf("%d",&n)!=EOF)

    {

        int ans=0;

        memset(a,0,sizeof(a));

        memset(c,0,sizeof(c));

        for(int i=1;i<=n;i++)

        {

            scanf("%d",&a[i]);

            a[i]++;

            ans+=sum(n)-sum(a[i]);

            add(a[i],1);

        }

        int Min=ans;

        for(int i=1;i<=n;i++)

        {

            ans+=n-a[i]-(a[i]-1);

            if(ans<Min)Min=ans;

        }

        printf("%d\n",Min);

    }

    return 0;

}

人一我百!人十我萬!永不放棄~~~懷着自信的心,去追逐夢想。