逆序对(归并排序)

传送门 

第一思路是使用嵌套for循环进行解决,即枚举每一个数字后面比他小的数字并且进行计数,

但是对于该题的数据范围而言并不能完美解决

因此我们需要更好的思路

这里提供一种思路:利用归并排序的归并进行解答

首先我们知道,归并排序在每一次合并的时候,前后两个序列都是已经排好序的,例如在某个时候

存在左区间:5 6 7 下标为i

右区间:       1 2 9 下标为j

//这个时候我们进行合并:
//step 1:由于 5>1,所以产生了逆序对,这里,
我们发现,左区间所有还没有被合并的数都比 1 大(
因为区间内已经排好序了),
所以1与左区间所有元素共产生了 3 个逆序对(
即tot_numleft-(i-1)对),统计答案并合并 1 
//step 2:由于 5>2,由上产生了3对逆序对,统计答案并合并 2
//step 3:由于 5<9, 没有逆序对产生,右区间下标 j++
//step 4:由于 6<9, 没有逆序对产生,右区间下标 j++
//step 5:由于 7<9, 没有逆序对产生,右区间下标 j++
//step 6:由于右区间已经结束,正常执行合并左区间剩余,结束

据此,我们就可以完成代码的编写了

//归并排序
#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>

using namespace std;

const int MAX = 5e5 + 10;
int arr[MAX];
int temp[MAX];
long long ans = 0;//注意要开long long
int n;

void merge(int low, int mid, int high) {
	int i = low, j = mid + 1, k = low;
	while (i <= mid && j <= high) {
		if (arr[i] < arr[j]) {
			temp[k++] = arr[i++];
		}
		else {			
			temp[k++] = arr[j++];
			ans+=(mid-(i-1));//关键
		}
	}
	while (i <= mid)
		temp[k++] = arr[i++];
	while (j <= high)
		temp[k++] = arr[j++];
	for (int z = low; z <= high; z++) {
		arr[z] = temp[z];
	}
}

void mergeSort(int low, int high) {//左闭右闭 
	if (low < high) {//当存在2个或以上元素才进行排序 
		int mid = (high + low) / 2;
		mergeSort(low, mid);
		mergeSort(mid + 1, high);
		merge(low, mid, high);//合并 
	}
}

int main() {
	scanf("%d",&n);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &arr[i]);
	}
	mergeSort(1, n);
	/*for (int i = 1; i <= n; i++) {
		cout << arr[i] << " ";
	}*/
	printf("%lld", ans);
	return 0;
}

注意的是该题提示使用较快的输入,因此我们选择使用scanf输入

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZZZWWWFFF_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值