【题目链接】
【题目考点】
1. 归并排序 求逆序对数量
【解题思路】
逆序对:在数组a中,假设i < j
但a[i] > a[j]
,那么称a[i]
与a[j]
为一对逆序对。
考虑一对相邻的逆序的数字,在交换这两个数字后,逆序对数量减少了1,其余的逆序对并不受影响。
每次交换相邻的逆序数字,会减少1个逆序对。如果序列中存在逆序对,该序列就一定不是升序。
那么想要将整个序列变为升序,总交换次数即为原序列中逆序对的个数。
求逆序对数量效率较高的方法为归并排序求逆序对数,复杂度为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)。
归并排序求逆序对数量,可以参考:信息学奥赛一本通 1311:【例2.5】求逆序对 | 1237:求排列的逆序数
【题解代码】
解法1:归并排序求逆序对数量
#include<bits/stdc++.h>
using namespace std;
#define N 10005//数组长度
int a[N], t[N];
int ct;//逆序数
void mergeSort(int l, int r)
{
if(l >= r)
return;
int mid = (l + r)/2;
mergeSort(l, mid);
mergeSort(mid+1, r);
int ti = l, li = l, ri = mid+1;//li第一个段数组中的下标 ri第二段数组中的下标 ti临时数组中的下标
while(li <= mid && ri <= r)
{
if(a[li] <= a[ri])
t[ti++] = a[li++];
else//如果a[ri] < a[li] 此时a[ri]与左侧数组剩余的mid-li+1个数字构成逆序对
{
ct += mid-li+1;
t[ti++] = a[ri++];
}
}
while(li <= mid)
t[ti++] = a[li++];
while(ri <= r)
t[ti++] = a[ri++];
for(int i = l; i <= r; ++i)
a[i] = t[i];
}
int main()
{
int n;
cin >> n;
for(int i = 1; i <= n; ++i)
cin >> a[i];
mergeSort(1, n);
cout << ct;
return 0;
}