题目描述 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[],b[]; unsigned long long int ans=; void nxd(int l,int r)
{
if(l==r) return ;
int mid=(l+r)/;
nxd(l,mid),nxd(mid+,r);
int lik=l,rik=mid+,now=l-;
while(now<r)
{
if(lik<=mid&&rik<=r)
{
if(a[lik]<=a[rik])
{
b[++now]=a[lik++];
ans+=rik-mid-;
}
else b[++now]=a[rik++];
}
else
{
if(lik<=mid)
{
b[++now]=a[lik++];
ans+=rik-mid-;
}
else
{
b[++now]=a[rik++];
}
}
}
for(int i=l;i<=r;i++) a[i]=b[i];
} int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++) scanf("%d",&a[i]);
nxd(,n);
printf("%lld\n",ans);
return ;
}