NC15163 逆序数
题目
题目描述
在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。比如一个序列为 , 那么这个序列的逆序数为 ,逆序对分别为 (4, 1), (4, 3), (4, 2), (5, 1), (5, 3), (5, 2),(3, 2) 。
输入描述
第一行有一个整数 , 然后第二行跟着 个整数,对于第 个数 。
输出描述
输出这个序列中的逆序数
示例1
输入
5 4 5 1 3 2
输出
7
题解
知识点:递归,排序。
众所周知,排序可以理解为把一个具有逆序数的序列变换为逆序数为零的序列。而归并排序每次交换元素,只会导致逆序数减少,而且可以非常容易的计算。
归并排序先把序列对半分,直到只有一个元素(可视为排序好的)开始回溯进行排序。而将两个排序好的序列归并是很容易的,只要用两个指针 分别指向两个数组的头部开始遍历,再创建一个临时数组,依次哪个小就放哪个进临时数组,最后覆盖回去即可。在这个过程中,各自序列的元素的相对位置不会改变,而左序列元素和右序列各个元素的相对位置可能会发生改变。每次遇到一个左序列元素大于右序列元素,则将右序列元素提前,仅在这个过程会仅减少逆序数,值为 ,即左序列剩余元素个数。将每次归并减少的逆序数累加,就是最终答案。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> using namespace std; long long cnt = 0; int a[100007], b[100007]; void merge_sort(int l, int r) { if (l == r) return; int mid = l + r >> 1; merge_sort(l, mid); merge_sort(mid + 1, r); int i = l, j = mid + 1, k = l; while (i <= mid && j <= r) { if (a[i] <= a[j]) b[k++] = a[i++]; else b[k++] = a[j++], cnt += mid - i + 1; } while (i <= mid) b[k++] = a[i++]; while (j <= r) b[k++] = a[j++]; for (int i = l;i <= r;i++) a[i] = b[i]; } int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n; cin >> n; for (int i = 0;i < n;i++) cin >> a[i]; merge_sort(0, n - 1); cout << cnt << '\n'; return 0; }
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/16403630.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧