51 Nod 1019 逆序数(归并排序)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51 Nod 1019 逆序数(归并排序)相关的知识,希望对你有一定的参考价值。
题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1019
题意:在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。
如2 4 3 1中,2 1,4 3,4 1,3 1是逆序,逆序数是4。给出一个整数序列,求该序列的逆序数。
题解:逆序数的求法有两种,一种就是在冒泡排序的过程中求得(直接暴力枚举,也就是我们平常O(n^2)级别的求法)还有一种是在归并排序过程中求,这个的时间复杂度就可以降低到O(nlogn)
关于归并排序求逆序数,我举个栗子,一堆为(4 6 7 8),另一堆为(2 6)。我们先把第二堆中2归并进去,在第一堆中找到第一个比它大的数4,然后此时产生的逆序数为len1-i+1=4-1+1=4
同理6产生的逆序数为4-3+1=2。就是这个意思....
归并排序的思想很简单,就是先分开,排下序,然后合并。注意对数据的更新就好了。
1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 5 const int N=50000+10; 6 typedef long long LL; 7 8 LL cnt; 9 int num[N],result[N]; 10 11 void merge(int *num,int *result,int start,int end){ 12 int t=start,mid=(start+end)/2; 13 int i=start,j=mid+1; 14 while(i<=mid&&j<=end){ 15 if(num[i]<=num[j]) result[t++]=num[i++]; 16 else if(num[i]>num[j]){ 17 result[t++]=num[j++]; 18 cnt+=mid-i+1; 19 } 20 } 21 while(i<=mid) result[t++]=num[i++]; 22 while(j<=end) result[t++]=num[j++]; 23 for(int i=start;i<=end;i++) //更新 24 num[i]=result[i]; 25 } 26 27 void merge_sort(int *num,int *result,int start,int end){ 28 if(end-start==1){ 29 if(num[start]>num[end]){ 30 int tmp=num[start]; 31 num[start]=num[end]; 32 num[end]=tmp; 33 cnt++; 34 } 35 return ; 36 } 37 if(end-start==0) return ; 38 merge_sort(num,result,start,(end+start)/2); 39 merge_sort(num,result,(end+start)/2+1,end); 40 merge(num,result,start,end); 41 } 42 43 int main(){ 44 int n; 45 cin>>n; 46 for(int i=1;i<=n;i++) cin>>num[i]; 47 merge_sort(num,result,1,n); 48 cout<<cnt<<endl; 49 return 0; 50 }
以上是关于51 Nod 1019 逆序数(归并排序)的主要内容,如果未能解决你的问题,请参考以下文章