POJ 2299 -- Ultra-QuickSort
Ultra-QuickSort
Time Limit: 7000MS | Memory Limit: 65536K | |
Total Submissions: 65986 | Accepted: 24686 |
Description
In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent sequence elements until the sequence is sorted in ascending order. For the input sequence
9 1 0 5 4 ,
Ultra-QuickSort produces the output
0 1 4 5 9 .
Your task is to determine how many swap operations Ultra-QuickSort needs to perform in order to sort a given input sequence.
Ultra-QuickSort produces the output
Your task is to determine how many swap operations Ultra-QuickSort needs to perform in order to sort a given input sequence.
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.
Sample Input
5
9
1
0
5
4
3
1
2
3
0
Sample Output
6
0
Source
题意:
输入n个数,问至少经过多少次两两交换,可以得到一个升序序列
n < 500,000 -- the length of the input sequence
0 ≤ a[i] ≤ 999,999,999
解题:
1)利用归并排序求逆序数
一个乱序序列的 逆序数 = 在只允许相邻两个元素交换的条件下,得到有序序列的交换次数
注意保存逆序数的变量t,必须要用__int64定义,int一定会溢出的,而long long 在现在的VC编译器已经无法编译了。
注意__int64类型的输出必须使用指定的c格式输出,printf(“%I64d”,t);
cout是无法输出__int64类型的
序列数组s[]用int就足够了,每个元素都是小于10E而已
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 int const maxa = 500005; 5 __int64 ans;//逆序数 6 int a[maxa];//存储n个数 7 8 void Merge(int left,int mid,int right) 9 { 10 int len_l = mid-left+1; 11 int len_r = right-mid; 12 int* aLeft = new int[len_l+2]; 13 int* aRight = new int[len_r+2]; 14 for(int i=1;i<=len_l;i++) 15 aLeft[i] = a[left+i-1]; 16 aLeft[len_l+1] = 10000000000;//设置一个很大的上界防止溢出 17 for(int i=1;i<=len_r;i++) 18 aRight[i] = a[i+mid]; 19 aRight[len_r+1] = 10000000000;//设置一个很大的上界防止溢出 20 int m=1,n=1; 21 for(int i=left;i<=right;i++) 22 { 23 if(aLeft[m] <= aRight[n]) 24 { 25 a[i] = aLeft[m];m++; 26 } 27 else{ 28 ans+=len_l-m+1; 29 a[i] = aRight[n];n++; 30 } 31 } 32 delete aLeft; 33 delete aRight; 34 return; 35 36 } 37 38 void mergeSort(int left,int right) 39 { 40 if(left<right) 41 { 42 int mid = (left + right)/2; 43 mergeSort(left,mid); 44 mergeSort(mid+1,right); 45 Merge(left,mid,right); 46 } 47 return; 48 } 49 50 int main() 51 { 52 int n; 53 while(cin>>n && n!=0) 54 { 55 for(int i=1;i<=n;i++) 56 cin>>a[i]; 57 ans = 0; 58 mergeSort(1,n); 59 printf("%I64d\n",ans); 60 } 61 62 return 0; 63 }
为什么要使用归并呢?这是因为输入的数据量可能会达到50W
下图的测试是使用插入排序,不出意外的超时了
所以使用归并排序,时间复杂度为O(nlogn)
只有堆排序和归并排序时间复杂度可以控制在O(nlogn),因为他们都用用空间换时间,其他的排序算法在最坏的情况下,时间复杂度均为O(n^2)
2)树状数组
树状数组例题(poj2299)
记录一下,以后再学习……