逆序对
题目描述
ZZR 有一个序列 a1,a2,⋯,an,他允许最多进行 k 次操作,每次操作交换两个相邻元素。
求经过变换后的序列中最少还有多少逆序对。
逆序对指的是二元组 (i,j),其满足 i<j 且 ai>aj。
输入描述
第一行包含两个数 n,k,表示序列长度和交换两个相邻元素的次数上限。
第二行有 n 个数,表示序列 a1,a2,⋯,an。
输出描述
一个数表示最少的逆序对的数量。
用例输入 1
3 1
2 2 1
用例输出 1
1
用例输入 2
3 0
2 2 1
用例输出 2
2
数据规模与约定
1 ≤ n ≤ 1 0 5 , 0 ≤ k ≤ 1 0 9 , 1 ≤ a i ≤ 1 0 9 。 1≤n≤10^5,0≤k≤10^9,1≤a_i≤10^9。 1≤n≤105,0≤k≤109,1≤ai≤109。
思路
我们知道归并排序可以计算逆序对数量,而在逆序对存在的情况下,每次交换某个具有相邻元素的逆序对所对应的元素都可以使得逆序对减少一个。那么只要求出逆序对的数量,本题答案就显而易见了。
代码
#include <bits/stdc++.h>
using namespace std;
#define max_Heap(x) priority_queue<x, vector<x>, less<x>>
#define min_Heap(x) priority_queue<x, vector<x>, greater<x>>
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<long long, long long> PLL;
const int maxn = 1e5 + 10;
int q[maxn], tmp[maxn];
ll ans;
void merge_sort(int q[], int l, int r)
{
if (l >= r)
return; // 如果l>=r,无需排序
int mid = (l + r) / 2;
merge_sort(q, l, mid); // 分解左序列
merge_sort(q, mid + 1, r); // 分解右序列
int k = l, i = l, j = mid + 1;
while (i <= mid && j <= r) // 合并
{
if (q[i] <= q[j])
tmp[k++] = q[i++];
else
{
tmp[k++] = q[j++];
ans += mid - i + 1; // 统计产生逆序对的数量
}
}
while (i <= mid)
tmp[k++] = q[i++]; // 复制左边子序列剩余
while (j <= r)
tmp[k++] = q[j++]; // 复制右边子序列剩余
for (int i = l; i <= r; i++)
q[i] = tmp[i];
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
// 如果序列存在逆序对,则每交换两个元素,都可以使得逆序对减少一个
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; i++)
{
cin >> q[i];
}
merge_sort(q, 1, n);
if (k >= ans) // 如果可交换次数大于等于逆序对数量,则可以将逆序对减少为0
{
cout << 0 << '\n';
}
else // 如果逆序对比交换次数多,答案为逆序对数量减去可交换次数
{
cout << ans - k << '\n';
}
return 0;
}