HDU 1394 Minimum Inversion Number(求逆序数,线段树或者树状数组)

Minimum Inversion Number

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 4647    Accepted Submission(s): 2809


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
 

 

Recommend
Ignatius.L
 
 
 
本题就是求循环移位后逆序数的最小值。
其实主要就是求序列的逆序数。
逆序数的求法很多,可以用归并排序求。
也可以用树状数组和线段树求逆序数。
 
逆序数求得之后,把第一个数移到最后的逆序数是可以直接得到的。
比如原来的逆序数是ans,把a[0]移到最后后,减少逆序数a[0],同时增加逆序数n-a[0]-1个
就是ans-a[0]+n-a[0]-1;
 
只要i从0-n-1循环一遍取最小值就可以了。
 
 
线段树的做法:
/*

HDU 1394

G++ 78ms 280K



*/



#include<stdio.h>

#include<string.h>

#include<algorithm>

using namespace std;

const int MAXN=5050;

struct Node

{

    int l,r;

    int sum;

}segTree[MAXN*3];

void Build(int i,int l,int r)

{

    segTree[i].l=l;

    segTree[i].r=r;

    if(l==r)

    {

        segTree[i].sum=0;

        return;

    }

    int mid=(l+r)>>1;

    Build(i<<1,l,mid);

    Build((i<<1)|1,mid+1,r);

    segTree[i].sum=0;

}

void add(int i,int t,int val)

{

    segTree[i].sum+=val;

    if(segTree[i].l==segTree[i].r)

    {

        return;

    }

    int mid=(segTree[i].l+segTree[i].r)>>1;

    if(t<=mid) add(i<<1,t,val);

    else add((i<<1)|1,t,val);

}

int sum(int i,int l,int r)

{

    if(segTree[i].l==l&&segTree[i].r==r)

      return segTree[i].sum;

    int mid=(segTree[i].l+segTree[i].r)>>1;

    if(r<=mid) return sum(i<<1,l,r);

    else if(l>mid)  return sum((i<<1)|1,l,r);

    else return sum(i<<1,l,mid)+sum((i<<1)|1,mid+1,r);

}

int a[MAXN];

int main()

{

  //  freopen("in.txt","r",stdin);

  //  freopen("out.txt","w",stdout);

    int n;

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

    {

        Build(1,0,n-1);

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

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

        int ans=0;

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

        {

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

            add(1,a[i],1);

        }

        int Min=ans;

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

        {

            ans-=a[i];//减少的逆序数

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

            if(ans<Min)Min=ans;

        }

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

    }

    return 0;

}

 

 

树状数组:

/*

HDU 1394

AC  G++ 46ms 252k



*/





#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(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;

}

 

你可能感兴趣的:(version)