Young87

SmartCat's Blog

So happy to code my life!

游戏开发交流QQ群号60398951

当前位置:首页 >跨站数据测试

POJ_2299_Ultra-quicksort_归并排序、逆序数

这题是好多天前做的,不知道怎么回事没有写题解。


题意:

给你一个神秘的排序,其实就是冒泡排序,给一个序列,问用这个神秘的排序要进行多少词swap操作。

Input

The input contains several test cases. Every test case begins with a line that contains a single integer n < 500,000 -- the length of the input sequence. Each of the the following n lines contains a single integer 0 ≤ a[i] ≤ 999,999,999, the i-th input sequence element. Input is terminated by a sequence of length n = 0. This sequence must not be processed.

Output

For every input sequence, your program prints a single line containing an integer number op, the minimum number of swap operations necessary to sort the given input sequence.
最朴素的想法就是冒泡排序,加一个变量记录swap次数。但是冒泡O(n^2)的复杂度,对5*10^5显然是不行的。

这个题要用一个数学知识,就是线性代数里的逆序数,然后TM我们学校学的那本外文的线代提都没提啊哦凑!!

对一个数列只通过交换相邻的两个数,从而把这个序列调整为有序所需要的步骤(这就是答案啊哦凑),等于这个序列所有数的逆序数之和。

逆序数就是在这个数后面的,但是应该排在这个数前面的数的个数。

数学知识说完了,那么就可以把答案转化为求序列逆序数和,就可以用别的排序来做,在排序的同时,统计逆序数,所以选择比较快的两个O(nlogn)排序算法之一的我还记得该怎么写的归并排序。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
#define mxn 500010
int n;
int a[mxn];
long long sum;
long long merge(int l,int r){
	int m=(l+r)/2;
	int tem[mxn];
	int ls=l,rs=m+1,cnt=0;
	long long ret=0;
	while(ls!=m+1||rs!=r+1){
		if(ls==m+1)	tem[cnt++]=a[rs++];
		else if(rs==r+1)	tem[cnt++]=a[ls++];
		else if(a[ls]<a[rs])	tem[cnt++]=a[ls++];
		else{
			tem[cnt++]=a[rs++];
			ret+=m-ls+1;
		}
	}
	for(int i=l;i<=r;++i)	a[i]=tem[i-l];
	return ret;
}
long long merge_sort(int l,int r){
	if(l==r)	return 0;
	int m=(l+r)/2;
	long long ret=0;
	ret+=merge_sort(l,m)+merge_sort(m+1,r);
	ret+=merge(l,r);
	return ret;
}
int main(){
	sum=0;
	while(scanf("%d",&n)!=EOF&&n){
		for(int i=0;i<n;++i)	scanf("%d",&a[i]);
		long long ans=merge_sort(0,n-1);
		printf("%lld\n",ans);
	}
	return 0;
}


除特别声明,本站所有文章均为原创,如需转载请以超级链接形式注明出处:SmartCat's Blog

上一篇: C语言库函数stdlib.h里面都包含什么

下一篇: 01背包

精华推荐