[C++] AcWing 788. 逆序对的数量

本文详细讲解了如何通过归并排序计算整数数组的逆序对数量,涉及递归、分区操作和代码示例。
摘要由CSDN通过智能技术生成

逆序对的数量

前言

只是记录

题目

思路

  • 什么是逆序对?
    在一个序列里,对于第 i 个和第 j 个元素,如果满足 i<j 且 a[i] > a[j],那么 (a[i],a[j[)就是一个逆序对。要注意的是: 如果有 k<i<j 且 a[k] > a[i] > a[j],那么 (a[k],a[i]) 和(a[k],a[j])是两个逆序对。
    举个栗子:
序列逆序对
1 3 2(3,2)
2 3 1(2,1) ,(3,1)
  • 归并排序
    1. 将[l,r] => [l,mid] + [mid+1,r]
    2. 将两个区间递归排序
    3. 合并
  • 将逆序对分为三类
    1. 两个元素都在左区间
    2. 两个元素都在右区间
    3. 两个元素一个在左,一个在右
  • 所以在计算的时候需要
    1. 递归算左边的
    2. 递归算右边的
    3. 算一左一右的
    4. 加起来
  • 注意: 左右两边的元素在各自任意调换顺序,是不影响第三步计数的,因此我们可以数完就给它排序。这么做的好处在于,如果序列是有序的,会让第三步计数很容易。
    举个栗子:
    4 5 6 | 1 2 3
    4 >1,左边最小的数都大于1,那4后面的数肯定都大于1,所以直接算mid-i+1(也就是左区间有几个数就行。为什么要+1:就像1 2 3 有 (3-1)+1 个数)。

代码

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
long long merge_sort(int q[], int l, int r)//用int不会过
{
	if(l>=r)// if(l==r) 也可以
		return 0;
	int temp[N];
	int mid=l+r>>1;// => (l+r)/2
	int k=0,i=l,j=mid+1;//分成两个区间
	long long ans=0;
	ans+=merge_sort(q,l,mid)+merge_sort(q,mid+1,r);//递归排序并求逆序对数量
	while(i<=mid&&j<=r)
	{
		if(q[i]<=q[j])
			temp[k++]=q[i++];
		else // i<j 且 q[i]>q[j]
		{
			temp[k++]=q[j++];
			ans+=mid-i+1;//因为 i 指向的数比 j 指向的数大,所以[i,mid]指向的的数比 j 指向的数都大,直接算有几个数(mid-i+1)
		}
	}
	//左右区间中至少有一个区间的数已经全部放到temp数组了
	while(i<=mid)//左边区间的数还有剩余的,直接放到temp里
		temp[k++]=q[i++];
	while(j<=r)//右边区间还有剩余的,直接放到temp里
		temp[k++]=q[j++];
	for(i=l,j=0;i<=r;i++,j++)
		q[i]=temp[j];
	return ans;
}
int main()
{
	int n;
	cin>>n;
	int q[N];
	for(int i=0;i<n;i++)
		cin>>q[i];
	long long ans=merge_sort(q,0,n-1);
	cout<<ans<<endl;
	return 0;
}

题目链接

788. 逆序对的数量

  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值