求逆序数(归并排序)

逆序数:一个数列中逆序对的个数

比如将下面两个区间排序
ai mid=4 aj
3 4 7 9 1 5 8 10
首先将右区间的1取出,放到c中,此时1是比每个ai的元素都小,
也就是说此时i的指针指向a1的位置,此刻得到的逆序对的数量为4;
c=1;
然后再将ai和aj比较(直到ai<aj) ,ai<aj将ai的元素放到c中;
c=1 3 4;
现在aj>ai, i指向a3的位置, 将5放到c中, 得到的逆序对数量为2;
c=1 3 4 5;
以此类推 ,直到进行完归并排序,每次合并都会求出逆序对的数目,即
mid-i+1, 最后每次将ans加上mid-i+1 即可得到最后的答案;

或者 再来个栗子

在某个时候,左区间: 5 6 7 下标为i
右区间: 1 2 9 下标为j

这个时候我们进行合并:
step 1:由于 5>1,所以产生了逆序对,这里,我们发现,左区间所有还没有被合并的数都比 1 大,所以1与左区间所有元素共产生了 3 个逆序对(即tot_numleft-i+1对),统计答案并合并 1
step 2:由于 5>2,由上产生了3对逆序对,统计答案并合并 2
step 3:由于 5<9, 没有逆序对产生,右区间下标 j++
step 4:由于 6<9, 没有逆序对产生,右区间下标 j++
step 5:由于 7<9, 没有逆序对产生,右区间下标 j++
step 6:由于右区间已经结束,正常执行合并左区间剩余,结束

PS: tot_numleft=3,即左区间总元素个数;

例题可见:https://www.luogu.org/problemnew/show/P1908

代码

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<string>
#include<vector>
#include<math.h>
#include<algorithm>
#include<map>
#include<set> 
#include<stack>
#include<cctype>
#include<queue>
#define ll long long
//	freopen("D:\\in.txt" ,"r" ,stdin);
//  freopen("D:\\out.txt" ,"w" ,stdout);
using namespace std; 
int n,a[500005],c[500005];
ll ans; 

void msort(int b,int e)
{
	if(b==e) return ;
	int mid=(b+e)/2;
	int i=b;
	int j=mid+1;
	int k=b;
	msort(b,mid);
	msort(mid+1,e);
	while(i<=mid&&j<=e)
	{
		if(a[i]<=a[j])
		{
			c[k++]=a[i++];
		}
		else 
		{
			c[k++]=a[j++];
			ans+=mid-i+1;
		}
	}
	while(i<=mid) c[k++]=a[i++];
	while(j<=e) c[k++]=a[j++];
	for(int i=b;i<=e;i++)
	{
		a[i]=c[i];
	}
}

int main(void)
{
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	msort(1,n);
	cout<<ans<<endl;
	return 0;
}

转载:https://www.luogu.org/blog/cpp/solution-p1908
https://www.luogu.org/blog/user49618/solution-p1908

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值