P1908 逆序对
P1908 逆序对
https://www.luogu.com.cn/problem/P1908
题目描述
猫猫 TOM 和小老鼠 JERRY 最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。
最近,TOM 老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中 ai > aj且 i<j的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。注意序列中可能有重复数字。
Update:数据已加强。
输入格式
第一行,一个数 n,表示序列中有 n个数。
第二行 n 个数,表示给定的序列。序列中每个数字不超过 10^9。
输出格式
输出序列中逆序对的数目。
思路
题目数据很大,显然不能用O(n2)的冒泡做,所以选择效率更高的归并排序,本体相比普通的归并排序,只需要加上一条语句
ans += mid - i + 1;
逆序对的数量等于每一次发现 ai > aj 时 i 到 mid 的元素个数,因为 aj 比这些数都要小。
代码
#include<bits/stdc++.h> using namespace std; int a[500010]; int b[500010]; using ll = long long; ll ans = 0; void mergesort(int l, int r) { if (l == r) return; int mid = (l + r) / 2; mergesort(l, mid); mergesort(mid + 1, r); int i = l; int j = mid + 1; int k = l; while (i <= mid && j <= r) { if (a[i] <= a[j]) b[k++] = a[i++]; else { b[k++] = a[j++]; ans += 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() { ios::sync_with_stdio(false); cin.tie(0); int n; cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; mergesort(1, n); cout << ans << "\n"; return 0; }