AcWing 788. 逆序对的数量
前置知识 归并排序
不会的点这里QwQ
逆序对算法
定义
逆序对的定义如下:对于数列的第 个和第 个元素,如果满 且 ,则其为一个逆序对;否则不是。
分析
用分治算法解决。
我们将序列从中间分开,将逆序对分成三类:
- 两个元素都在左边;
- 两个元素都在右边;
- 两个元素一个在左一个在右。
我们可以推出大概流程:
- 算左边的;
- 算右边的;
- 算一左一右的;
- 相加。
如何计算
我们发现一个性质:当数组分为左右两部分时,其中一个部分中的数字位置进行了交换并不会影响另外一部分与该部分之间产生的逆序对数(也就是“一左一右”的情况)。 根据归并排序流程,发现可以用归并排序排序。
有什么好处?
如果右侧指针指向的数字小于左侧指针指向的数字,那么说明左侧指针所指向的数字以及该序列之后的数字均大于右侧指针所指向的数字,所及将这些数字全部记录,ans += mid - i + 1
即可。
算法时间复杂度
与归并排序相同,复杂度 。
代码实现
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;
const int N = 100010;
long long n, a[N], ans, r[N];
void nxd(long long s, long long t)
{
long long mid = (s + t) / 2, i = s, j = mid + 1, k = s;
if (s == t) return;
nxd(s, mid);
nxd(mid + 1, t);
while (i <= mid && j <= t)
{
if (a[i] <= a[j]) r[k] = a[i], i ++ , k ++ ;
else r[k] = a[j], j ++ , k ++ , ans += mid - i + 1; // ans累加答案,其他部分与归并排序相同,不做解释
}
while (i <= mid) r[k] = a[i], i ++ , k ++ ;
while (j <= t) r[k] = a[j], j ++ , k ++ ;
for (int i = s; i <= t; i ++ ) a[i] = r[i];
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i ++ ) cin >> a[i];
nxd(1, n);
cout << ans;
return 0;
}
本文来自博客园,作者:FXT1110011010OI,转载请注明原文链接:https://www.cnblogs.com/FXT1110011010OI/p/16421076.html
分类:
C ++ 算法
, ACWING 基础课
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)