逆序对 洛谷P1908

使用归并排序计算逆序对数量
这篇博客介绍了如何利用分治和归并排序的思路解决逆序对计数问题。在给定的正整数序列中,逆序对是指较小的数位于较大的数之后的数对。传统暴力方法效率低下,因此采用归并排序的思想,在排序过程中统计逆序对。通过将序列分为两部分,比较边界元素并更新逆序对计数,最后将结果输出。代码示例展示了如何实现这一算法,适用于规模较大的数据集。

题目描述

猫猫 TOM 和小老鼠 JERRY 最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。

最近,TOM 老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中 ai>aja_i>a_jai>aji<ji<ji<j 的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。注意序列中可能有重复数字。

输入格式

第一行,一个数 nnn,表示序列中有 nnn个数。
第二行 nnn 个数,表示给定的序列。序列中每个数字不超过 10910^9109

输出格式

输出序列中逆序对的数目。

样例

输入1

6
5 4 2 6 3 1

输出1

11	

规模说明

对于 25%25\%25% 的数据,n≤2500n \leq 2500n2500

对于 50%50\%50% 的数据,n≤4×104n \leq 4 \times 10^4n4×104

对于所有数据,n≤5×105n \leq 5 \times 10^5n5×105

暴力

直接两重循环进行暴力,TTL

思路:分治+归并排序的思想

思路描述

由于暴力的做法效率低下,考虑如下场景。

将一个数列 a[]a[]a[] 分成两个有序数列 al[]a_l[]al[]ar[]a_r[]ar[]

  1. 如果能找到边界的 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 个逆序对。
  2. 如果 al[i]≤ar[j]a_l[i] \leq a_r[j]al[i]ar[j],则说明没有找到边界的 i,ji,ji,jiii 自加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]

序号ij情况操作
100al[i]>ar[j]a_l[i] > a_r[j]al[i]>ar[j]res+=4; j++;
201al[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);
	}
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值