求逆序对
输入一个序列{a1, a2, a3,…, an},交换任意两个相邻元素,不超过k次。交换之后,问最少的逆序对有多少个。
序列中的一个逆序对,是指存在两个数ai和aj,有ai > aj且1≤i<j≤n。也就是说,大的数排在小的数前面。
输入:第一行是n和k,1 ≤ n ≤ 105,0 ≤ k ≤ 109;第二行包括n个整数{a1, a2, a3,…, an},0≤ ai ≤109。
输出:最少的逆序对数量。
Sample Input:
3 1
2 2 1
Sample Output:
1
思路:
(1)在子序列内部,元素都是有序的,不存在逆序对;逆序对只存在于不同的子序列之间。
(2)合并两个子序列时,如果前一个子序列的元素比后面子序列的元素小,那么不产生逆序对;如果前一个子序列的元素比后面子序列的元素大,就会产生逆序对。
(3)交换两个相邻元素最多减少一个逆序对
#include <iostream>
#include<vector>
using namespace std;const int maxn = 105;
int cnt;
int b[maxn]; //辅助数组
void merge_sort(vector<int>& a, int left, int right) {
if (right - left > 0) {
// 1、尽量划分为数量相等的2个子序列,并排序
int mid = (left + right) / 2;
merge_sort(a, left, mid);
merge_sort(a, mid + 1, right);// 2、将2个有序的序列合并成一个有序序列
int i = left; // 辅助数组的下标
int p = left, q = mid + 1; //p、q分别指向2个序列的头部
while (p <= mid || q <= right) {
if (q > right || (p <= mid && a[p] <= a[q]))
b[i++] = a[p++];
else {
b[i++] = a[q++];
cnt += mid - p + 1;
}
}// 3、将辅助数组b中排好序的元素复制到a中
for (int i = left; i <= right; i++)
a[i] = b[i];
}
}
int main(){
int n, k;
cin >> n >> k;
vector<int>a(n);
for (int i = 0; i < n; i++)
cin >> a[i];
cnt = 0;
merge_sort(a, 0, n - 1);
if (cnt <= k) //交换两个相邻元素最多减少一个逆序对
cout << 0 << endl;
else
cout << cnt - k << endl;
return 0;}
参考blog:
归并排序之求逆序对_归并排序求逆序对_TINY_SPOT的博客-CSDN博客