Description
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
Output
Sample Input
5 9 1 0 5 4 3 1 2 3 0
Sample Output
6 0
本题其实只要是明白了归并排序,至于分治思想和逆排序就很简单了
归并法排序
思想概述:其实归并排序就是分治思想的一种应用,就是每次用二分的方式,每次将序列分成两部分,然后知道分成每一部分两个数为止,
在这一整块作为一部分,依次从该该整区间的左区间第一个数开始和右边(即从mid右面的)第一个数作比较,将小的放到合并序列中
这样就将该小的范围排好序了。之后一次排序,知道当前区间为整个大区间为止(详解http://blog.csdn.net/u014665013/article/details/38035359)
分治思想 http://www.doc88.com/p-98237060283.html
题目本质就是求逆序对了,简单介绍一下。逆序对是指在序列{a0,a1,a2...an}中,若ai<aj(i>j),则(ai,aj)上一对逆序对。而逆序数顾名思义就是序列中逆序对的个数。例如: 1 2 3是顺序,则逆序数是0;1 3 2中(2,3)满足逆序对的条件,所以逆序数只有1; 3 2 1中(1,2)(1,3)(2,3)满足逆序对,所以逆序是3。由定义不能想象,序列n的逆序数范围在[0,n*(n-1)/2],其中顺序时逆序数为 0,完全逆序时逆序数是n*(n-1)/2。
可以利用归并排序时计算逆序个数,时间复杂度是nlog2n,而空间复杂度2n。 利用归并求逆序是指在对子序列s1和s2在归并时,若s1[i]>s2[j](逆序状况),则逆序数加上s1.length-i,因为s1中i后面的数字对于s2[j]都是逆序的。
#include <cstdio> #include <iostream> using namespace std; #define MAX 500001 int n, a[MAX], t[MAX]; //a[]为输入序列 t[]为合并序列 应该注意的是,每次t[]数列都是临时的, //只在每次当前区间的排序中记录有序序列 __int64 sum; //逆序对个数 // 归并 void Merge(int l, int m, int r) { //p指向输出区间 int p = 0; //i、j指向2个输入区间 int i=l, j=m+1; //2个输入区间都不为空时 while(i<=m && j<=r) { // 取关键字小的记录转移至输出区间 if(a[i]>a[j]) //在左边的区间的当前访问的数大于右区间的 { t[p]=a[j]; //将右区间数合并到合并数列中 p++; j++; //如果合并了,就将右区间的加1 <span style="color:#ff0000;">sum+=m-i+1; </span> //a[i]后面的数字对于a[j]都是逆序的 例如1(L) 2 7 9 10(mid) 3 4 6 7 8 (r) ^(当前位置)这样在7后面的(当然 小于 =10)的所有数就都大于后面的了所以这样加 } else //在左边的区间的当前访问的数小于或等于右区间的 { t[p] = a[i]; //将左区间数合并到合并数列中 p++; i++; } } while(i <= m) //如果左区间中还存在没有进入合并序列的数,就让剩下的进合并序列 t[p++] = a[i++]; while(j <= r) //如果左区间中还存在没有进入合并序列的数,就让剩下的进合并序列 t[p++] = a[j++]; for (i=0; i<p; i++) // 归并完成后将结果复制到原输入数组 a[l+i] = t[i]; } // 归并排序 void MergeSort(int l, int r) { int m; if (l<r) { // 将长度为n的输入序列分成两个长度为n/2的子序列 m = (l+r)/2; MergeSort(l, m);// 对两个子序列分别进行归并排序 MergeSort(m + 1, r); <span style="color:#cc0000;"> Merge(l, m, r);//子序列合并成最终有序序列 //其实完全可以将Merge()函数放在该位置 </span> } } int main() { int i; while(1) { scanf("%d", &n); if (n == 0) break; sum=0; for(i = 0; i < n; i++) scanf("%d", &a[i]); MergeSort(0, n-1); printf("%I64d\n", sum); } //system("pause"); return 0; }