题目描述
猫猫 TOM 和小老鼠 JERRY 最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。
最近,TOM 老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中 ai>aja_i>a_jai>aj 且 i<ji<ji<j 的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。注意序列中可能有重复数字。
输入格式
第一行,一个数 nnn,表示序列中有 nnn个数。
第二行 nnn 个数,表示给定的序列。序列中每个数字不超过 10910^9109 。
输出格式
输出序列中逆序对的数目。
样例
输入1
6
5 4 2 6 3 1
输出1
11
规模说明
对于 25%25\%25% 的数据,n≤2500n \leq 2500n≤2500
对于 50%50\%50% 的数据,n≤4×104n \leq 4 \times 10^4n≤4×104。
对于所有数据,n≤5×105n \leq 5 \times 10^5n≤5×105
暴力
直接两重循环进行暴力,TTL
思路:分治+归并排序的思想
思路描述
由于暴力的做法效率低下,考虑如下场景。
将一个数列 a[]a[]a[] 分成两个有序数列 al[]a_l[]al[] 和 ar[]a_r[]ar[]
- 如果能找到边界的 i,ji, ji,j 使得 al[i]>ar[j]a_l[i] > a_r[j]al[i]>ar[j],那么就可以一次性得到 len(al)−ilen(a_l)-ilen(al)−i 个逆序对。
- 如果 al[i]≤ar[j]a_l[i] \leq a_r[j]al[i]≤ar[j],则说明没有找到边界的 i,ji,ji,j,iii 自加1。
【例】
al[]=[2,4,7,8]a_l[] = [2,4,7,8]al[]=[2,4,7,8], ar[]=[1,5,9,12]a_r[] = [1,5,9,12]ar[]=[1,5,9,12]
| 序号 | i | j | 情况 | 操作 |
|---|---|---|---|---|
| 1 | 0 | 0 | al[i]>ar[j]a_l[i] > a_r[j]al[i]>ar[j] | res+=4; j++; |
| 2 | 0 | 1 | al[i]≤ar[j]a_l[i] \leq a_r[j]al[i]≤ar[j] | i++ |
| … | … | … | … | … |
代码
int n;
long res = 0;
int[] a = new int[500004];
int[] c = new int[500004];
void msort(int l, int r) {
if(l==r) return;
int mid = (l+r)/2, i = l, j = mid+1, k = l;
msort(l, mid);
msort(mid+1, r);
while(i <= mid && j <= r) {
if(a[i] <= a[j]) {
c[k++] = a[i++];
} else {
c[k++] = a[j++];
res += mid-i+1;
}
}
while(i <= mid) c[k++] = a[i++];
while(j <= r) c[k++] = a[j++];
for(int z = l; z <= r; z++) a[z] = c[z];
}
void test() throws IOException {
Reader cin = new Reader();
n = cin.nextInt();
for(int i = 1; i <= n; i++) {
a[i] = cin.nextInt();
}
msort(1, n);
System.out.println(res);
}
使用归并排序计算逆序对数量
这篇博客介绍了如何利用分治和归并排序的思路解决逆序对计数问题。在给定的正整数序列中,逆序对是指较小的数位于较大的数之后的数对。传统暴力方法效率低下,因此采用归并排序的思想,在排序过程中统计逆序对。通过将序列分为两部分,比较边界元素并更新逆序对计数,最后将结果输出。代码示例展示了如何实现这一算法,适用于规模较大的数据集。
1514

被折叠的 条评论
为什么被折叠?



