题目描述
Description
给定一个序列a1,a2,…,an,如果存在i<j并且ai>aj,那么我们称之为逆序对,求逆序对的数目
数据范围:N<=105。Ai<=105。时间限制为1s。
输入描述
Input Description
第一行为n,表示序列长度,接下来的n行,第i+1行表示序列中的第i个数。
输出描述
Output Description
所有逆序对总数.
样例输入
Sample Input
4
3
2
3
2
样例输出
Sample Output
3
数据范围及提示
Data Size & Hint
思路:
经历了这么多的算法和结构
唯独没碰到过归并排序
今天整理考试题目
猛然发现有一个题需要用归并排序来求逆序对
所以
现在拿个水题练练手
因为没有接触过归并排序
只知道归并排序要用递归来写
所以自己摸索着写还是很吃力
但我还是很顽强的写了出来
归并排序
首先定义变量l,r
然后二分
二分到l==r就return
接下来就是排序
mid=(l+r)/2
把l到r分成两段
以mid为分界线
然后定义一个用于存储排序后的序列的数组
定义两个记录两个区间排序情况的指针lik,rik
if(a[lik]<=a[rik]) b[++now]=a[lik];
就这样直到lik==mid,rik==r
然后b数组已经赋值的部分排序到a数组相应的区间内
然后在排序的同时记录逆序对的个数即可
来,上代码:
#include<cstdio> using namespace std; int n,a[100001],b[100001]; unsigned long long int ans=0; void nxd(int l,int r) { if(l==r) return ; int mid=(l+r)/2; nxd(l,mid),nxd(mid+1,r); int lik=l,rik=mid+1,now=l-1; while(now<r) { if(lik<=mid&&rik<=r) { if(a[lik]<=a[rik]) { b[++now]=a[lik++]; ans+=rik-mid-1; } else b[++now]=a[rik++]; } else { if(lik<=mid) { b[++now]=a[lik++]; ans+=rik-mid-1; } else { b[++now]=a[rik++]; } } } for(int i=l;i<=r;i++) a[i]=b[i]; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); nxd(1,n); printf("%lld\n",ans); return 0; }