1908 逆序对
1908 逆序对
难度:普及+/提高
题目类型:递归/分治
提交次数:1
涉及知识:归并排序
题目描述
猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。最近,TOM老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中ai>aj且i<j的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。
代码:
#include<iostream> using namespace std; const int N = 100010; int a[N]; int temp[N]; int ans; void merge(int l, int m, int r){ int i = l, k = l, j = m+1; while(i<=m&&j<=r){ if(a[i]>a[j]){ temp[k++] = a[j++]; ans+=m-i+1; } else temp[k++] = a[i++]; } while(i<=m) temp[k++] = a[i++]; while(j<=r) temp[k++] = a[j++]; for(i = l; i<=r; i++) a[i] = temp[i]; } void merge_sort(int l, int r){ if(l < r){ int mid = (l + r)/2; merge_sort(l, mid); merge_sort(mid+1, r); merge(l, mid, r); } } int main(){ int n, i; cin>>n; for(i = 1; i <= n; i++) cin>>a[i]; merge_sort(1, n); cout<<ans<<endl; return 0; }
备注:
很经典的一道题,结课考试也考过,思路就是利用归并排序的特点,在merge中加入“关键的一行”。主要目的是巩固归并排序,看了半天终于背下来了,程序是自己写的,而且居然一遍就写对了∩_∩,看来记忆力还行(其实是因为把每一行代码都理解吃透了才记住。。),如果不多写写肯定又忘了。那关键的一行,第一次看的时候还看不明白,感觉那时候自己好傻(好吧现在也不怎么聪明),很简单嘛,分别排序的过程不能改变跨组的逆序对,merge的时候如果a[i]>a[j](按理说a[j]应该是比最后一个a[i]大的),a[j]这样一抢了先,有多少个a[i]会很难过呢?自然就是m-i+1个了!嗯,这么解释清楚不清楚?反正我觉得比较清楚。以后不懂的细节还是要花时间细细想想。