洛谷 P1908 逆序对 Label:归并排序||树状数组
Posted Radiumlrb
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 P1908 逆序对 Label:归并排序||树状数组相关的知识,希望对你有一定的参考价值。
题目描述
猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。最近,TOM老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中ai>aj且i<j的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。
输入输出格式
输入格式:
第一行,一个数n,表示序列中有n个数。
第二行n个数,表示给定的序列。
输出格式:
给定序列中逆序对的数目。
输入输出样例
输入样例#1:
6 5 4 2 6 3 1
输出样例#1:
11
说明
对于50%的数据,n≤2500
对于100%的数据,n≤40000。
代码:解法一
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int N,a[100005],temp[100005],cnt; 7 8 void print(){ 9 for(int i=1;i<=6;i++){ 10 printf("%d ",a[i]); 11 } 12 puts(""); 13 } 14 15 void merge_sort(int l,int r){ 16 if(l>=r) return; 17 int mid=(l+r)>>1; 18 merge_sort(l,mid);merge_sort(mid+1,r); 19 20 21 int i=l,j=mid+1,point=l; 22 while(i<=mid&&j<=r){ 23 if(a[i]>a[j]){ 24 temp[point++]=a[j++]; 25 cnt+=(mid-i+1); 26 } 27 else{ 28 temp[point++]=a[i++]; 29 } 30 } 31 32 while(i<=mid) temp[point++]=a[i++]; 33 while(j<=r) temp[point++]=a[j++]; 34 35 for(int k=l;k<=r;++k) 36 a[k]=temp[k]; 37 // print(); 38 } 39 40 int main(){ 41 // freopen("01.txt","r",stdin); 42 43 scanf("%d",&N); 44 for(int i=1;i<=N;++i) 45 scanf("%d",&a[i]); 46 47 merge_sort(1,N); 48 49 printf("%d\n",cnt); 50 return 0; 51 }
暴力枚举的话,可以过两个点~
转载题解如下:http://blog.csdn.net/acdreamers/article/details/16849761
归并排序是将数列a[l,h]分成两半a[l,mid]和a[mid+1,h]分别进行归并排序,然后再将这两半合并起来。
在合并的过程中(设l<=i<=mid,mid+1<=j<=h),当a[i]<=a[j]时,并不产生逆序数;当a[i]>a[j]时,在
前半部分中比a[i]大的数都比a[j]大,将a[j]放在a[i]前面的话,逆序数要加上mid+1-i。因此,可以在归并
排序中的合并过程中计算逆序数.
以上是关于洛谷 P1908 逆序对 Label:归并排序||树状数组的主要内容,如果未能解决你的问题,请参考以下文章