第一思路是使用嵌套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输入
逆序对(归并排序)
最新推荐文章于 2024-11-02 09:55:19 发布