Minimum Inversion Number(线段树 or 技巧统计)

Minimum Inversion Number

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

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

      题意:

      给出N(0到5000)个数,这N个数属于0到N-1的其中一个数,任意输入这N个数的其中一个序列。求这个序列的逆序数,求完这个排列的逆序数后,将第一位后移到最后一位,故产生一共N种排列,求出这N种排列的最小逆序数。

 

      思路:

      乍一看完全没头绪要怎么做,可是进一步分析,可以得出一条关系式:

      设当前排列的逆序数为sum,第一个数所产生的的逆序数对为first,那么他所产生的逆序数必定为first。因为它是第一位数,并且这个序列是没有相同项的,如果第一个数为6的话,则在它后面的N-1位各不相同,并且由0到N除了6的数组成,那么后面必有0,1,2,3,4,5一共6个数小于它,并且有N-1-6大于6。所以当第一个数后移后,新的序列的逆序数为sum=sum-(first)+(N-1-first)。

      first是本身的值,所以已知,N是总数,也已知,那么关键就是算sum,就是一开始这个序列的逆序数sum。

      有两种方法:

      1.循环两次,每次以i为起点开始,用j来对i+1后面的数进行扫描,如果num[i]>num[j]则sum++,这样的话就是从后面的数进行判断;

      2.如果非得用线段树做的话,就要换一种思考方式做,从前面的数开始判断。在结构体中开一个c域,用来记录这个区域内有几个数,在插入一个数num[i]之前,先判断[num[i],N-1]这个范围内有几个数,用sum+=c来记录,循环判断所有的数后,sum即为这个序列的逆序数。

         比如这个样例1 3 6 9 0 8 5 7 4 2;那么插入1之前先判断1的前面有多少个大于1的数(sum+=0),然后到插入3的时候前面有多少个大于3的数(sum+=0),当到0的时候有4个大于0的数,则sum=4,直到最后一个数2,2的前面有7个大于2的数,所以sum+=7,最后得出来sum也是22。

 

    AC:

    Method 1:

 

#include<stdio.h>
int main()
{
	int num[5000+5];
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		int sum=0;
		int min;
		for(int i=1;i<=n;i++)
		 scanf("%d",&num[i]);
		for(int i=1;i<=n-1;i++)
		 for(int j=i+1;j<=n;j++)
		 	if(num[i]>num[j]) sum++;
		min=sum;
		for(int i=1;i<=n-1;i++)
		 {
		 	sum=sum-2*num[i]-1+n;
		 	min=min>sum?sum:min;
		 }
		printf("%d\n",min);
	}
	return 0;
}

    

 

   Method 2:

 

#include<stdio.h>
#define MAX 5000+5
typedef struct
{
	int l;
	int r;
	int c;
}node;
node no[MAX*3];
int num[MAX],fir[MAX];
int sum;

void build(int from,int to,int i)
{
	int mid=(from+to)/2;
	no[i].l=from;
	no[i].r=to;
	if(from==to)
	{
		no[i].c=0;
		return;
	}
	build(from,mid,2*i);
	build(mid+1,to,2*i+1);
	no[i].c=no[2*i].c+no[2*i+1].c;
}

void add(int a,int i)
{
	int mid=(no[i].l+no[i].r)/2;
	if(no[i].l==no[i].r&&no[i].l==a)
	{
		no[i].c++;
		return;
	}
	if(a<=mid)   add(a,2*i);
	if(a>=mid+1) add(a,2*i+1);
	no[i].c=no[2*i].c+no[2*i+1].c;
}

void find(int from,int to,int i)
{
	int mid=(no[i].l+no[i].r)/2;
	if(no[i].l==from&&no[i].r==to)
	{
		sum+=no[i].c;
		return;
	}
	if(from>=mid+1)   find(from,to,2*i+1);
	if(to<=mid)       find(from,to,2*i);
	if(from<=mid&&to>=mid+1)
	{
		find(from,mid,2*i);
		find(mid+1,to,2*i+1);
	}
}

int main()
{
	int n,min;
	while(scanf("%d",&n)!=EOF)
	{
		min=0;
		sum=0;
		for(int i=1;i<=n;i++)
	  		scanf("%d",&num[i]);
		build(0,n-1,1);
		for(int i=1;i<=n;i++)
		{
			find(num[i],n-1,1);
			add(num[i],1);
//插入前先判断
		}
		min=sum;
		for(int i=1;i<=n-1;i++)
		{
			sum=sum-2*num[i]-1+n;
			min=min>sum?sum:min;
		}
		printf("%d\n",min);
	}
	return 0;
}

 

 

    总结:

    1.题目说是”The input consists of a number of test cases.“所以也应该用EOF输入;

    2.不要害怕题目本质,进一步分析就能得出答案。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值