转自: http://user.qzone.qq.com/289065406/blog/1304259927

 

题目大意:

给出长度为n的序列,每次只能交换相邻的两个元素,问至少要交换几次才使得该序列为递增序列。

 

解题思路:

一看就是冒泡,交换一次记录一次就可以了

但是n的范围达到50W,冒泡O(n^2)的复杂度铁定超时(即使有7000ms,其实这是一个陷阱)

直接用快排又不符合题目的要求(相邻元素交换),快排是建立在二分的基础上的,操作次数肯定比在所要求的规则下的交换次数要更少

 

那么该怎么处理?

 

其实这题题目已经给出提示了:Ultra-QuickSort

特殊的快排,能和快排Quicksort相媲美的就是归并排序Mergesort了,O(nlogn)

 

但是用归并排序并不是为了求交换次数,而是为了求序列的 逆序数(学过《线代》的同学应该很熟悉了)

一个乱序序列的 逆序数 = 在只允许相邻两个元素交换的条件下,得到有序序列的交换次数

 

例如例子的

9 1 0 5 4

由于要把它排列为上升序列,上升序列的有序就是  后面的元素比前面的元素大

而对于序列9 1 0 5 4

9后面却有4个比9小的元素,因此9的逆序数为4

1后面只有1个比1小的元素0,因此1的逆序数为1

0后面不存在比他小的元素,因此0的逆序数为0

5后面存在1个比他小的元素4, 因此5的逆序数为1

4是序列的最后元素,逆序数为0

 

因此序列9 1 0 5 4的逆序数 t=4+1+0+1+0 = 6  ,恰恰就是冒泡的交换次数

 

PS:注意保存逆序数的变量t,必须要用__int64定义,int和long都是无法保存的。。。。会导致WA。 以前的long long 在现在的VC编译器已经无法编译了。

注意__int64类型的输出必须使用指定的c格式输出,printf(“%I64d”,t);

cout是无法输出__int64类型的

 

序列数组s[]用int就足够了,每个元素都是小于10E而已

 

 

[cpp] view plaincopy
 
  1. //Memory Time  
  2. //3768K 2422MS   
  3.   
  4. #include<iostream>  
  5. using namespace std;  
  6.   
  7. const int inf=1000000000;  //10E  
  8.   
  9. __int64 t; //s[]数列逆序数  
  10.   
  11. void compute_t(int* s,int top,int mid,int end)  
  12. {  
  13.     int len_L=mid-top+1;  
  14.     int len_R=end-mid;  
  15.   
  16.     int* left=new int[len_L+2];  
  17.     int* right=new int[len_R+2];  
  18.   
  19.     int i,j;  
  20.     for(i=1;i<=len_L;i++)  
  21.         left[i]=s[top+i-1];  
  22.     left[len_L+1]=inf;   //设置无穷上界,避免比较大小时越界  
  23.   
  24.     for(j=1;j<=len_R;j++)  
  25.         right[j]=s[mid+j];  
  26.     right[len_R+1]=inf;   //设置无穷上界,避免比较大小时越界  
  27.   
  28.     i=j=1;  
  29.     for(int k=top;k<=end;)  
  30.         if(left[i]<=right[j])  
  31.             s[k++]=left[i++];  
  32.         else  
  33.         {  
  34.             s[k++]=right[j++];  
  35.             t+=len_L-i+1;    //计算逆序数  
  36.         }  
  37.   
  38.     delete left;  
  39.     delete right;  
  40.   
  41.     return;  
  42. }  
  43.   
  44. void mergesort(int* s,int top,int end)  
  45. {  
  46.     if(top<end)  
  47.     {  
  48.         int mid=(top+end)/2;  
  49.         mergesort(s,top,mid);  
  50.         mergesort(s,mid+1,end);  
  51.         compute_t(s,top,mid,end);  
  52.     }  
  53.     return;  
  54. }  
  55.   
  56. int main(void)  
  57. {  
  58.     int n;  //序列长度  
  59.     while(cin>>n)  
  60.     {  
  61.         if(!n)  
  62.             break;  
  63.   
  64.         /*Input*/  
  65.   
  66.         int* s=new int[n+1];  
  67.         for(int i=1;i<=n;i++)  
  68.             cin>>s[i];  
  69.   
  70.         /*Merge-Sort*/  
  71.   
  72.         t=0;  //initial  
  73.         mergesort(s,1,n);  
  74.   
  75.         /*Output*/  
  76.   
  77.         printf("%I64d\n",t);  
  78.   
  79.         /*Relax*/  
  80.   
  81.         delete s;  
  82.   
  83.     }  
  84.     return 0;  
  85. }  
posted on 2013-04-21 21:56  andy071001  阅读(41)  评论(0)    收藏  举报