HDU 1394 Minimum Inversion Number (公式法)

一开始以为是POJ 2299 的翻版,归并排序求逆序数

于是写出了以下的超时代码:

#include <stdio.h>
#define inf 1000000000

int n;
int a[10010];
int minnixu;
int nixu;

int num[10010];

int bak[10010];

void mergesort (int L, int R)
{
	if (L >= R) return;

	int mid = (L + R) / 2;

	mergesort (L, mid);
	mergesort (mid + 1, R);

	for (int k = L; k <= R; ++k) bak[k] = num[k];

	int i = L, j = mid + 1;
	for (int k = L; k <= R; ++k)
		if (i <= mid && (j > R || bak[i] < bak[j])) {
			num[k] = bak[i];
			i ++;
		} else {
			num[k] = bak[j];
			nixu+=mid-i+1; 
			j ++;
		}
}

int main()
{
	while (scanf("%d",&n)!=EOF) {
		minnixu=inf;
		for (int i=0; i<n; i++) {
			scanf("%d",a+i);
			a[n+i]=a[i];
		}
		for (int i=0; i<n; i++) {
			nixu=0;
			for (int j=0; j< 2*n; j++)
				num[j]=a[j];
			mergesort(0+i,i+n-1);
			if(nixu<minnixu)
				minnixu=nixu;
		}
		
		printf("%d\n",minnixu);
	}
}

后来一想。。。这么做的复杂度是 n^2 * log(n) ,的确让人无法接受,于是着手分析题意:

题目中的数列是 0到n-1的全排列

也就是说,每当我们做一次移位操作(将首元素 a 移到尾部)移位后数列的逆序数为移位前的逆序数  -a  +  (n-1-a)   (-a是因为a之后有a个比a小的数,把a移到队尾,这些逆序将不存在;同理,+(n-1-a)是因为a之后有n-1-a个比a大的数,把a移到队尾,会形成相应的逆序)

于是利用此公式写出AC代码:

#include <stdio.h>
#define inf 1000000000

int n;
int a[10010];
int rs[10010];		//right small

int count;
int mincount;

int main()
{
	while (scanf("%d",&n)!=EOF) {
		count=0;
		mincount=inf;
			
			
		
		for (int i=0; i<n; i++) {
			scanf("%d",a+i);
			rs[i]=0;
		}
		
		for(int i=0; i<n; i++) {
			for(int j=i+1;j<n; j++) {
				if(a[j]<a[i])
					rs[i]++;
			}
		}
		
		for(int i=0;i<n;i++) {
			count+=rs[i];
		}
		
		if(count < mincount) mincount=count;
		
		for(int i=0;i<n;i++) {
			count+=n-1-a[i];
			count-=a[i];
			if(count < mincount) mincount=count;	
		}
		printf("%d\n",mincount);
	}
}

posted on 2011-07-20 15:31  Eucalyptus  阅读(261)  评论(0编辑  收藏  举报