Problem Description
bobo has a sequence a1,a2,…,an. He is allowed to swap two adjacent numbers for no more than k times.
Find the minimum number of inversions after his swaps.
Note: The number of inversions is the number of pair (i,j) where 1≤i<j≤n and ai>aj.
Input
The input consists of several tests. For each tests:
The first line contains 2 integers n,k (1≤n≤105,0≤k≤109). The second line contains n integers a1,a2,…,an (0≤ai≤109).
Output
For each tests:
A single integer denotes the minimum number of inversions.
Sample Input
3 1
2 2 1
3 0
2 2 1
Sample Output
1
2
大概意思:可以将相邻的两个数交换位置,最多可以交换k次,使得交换完后的逆序数最少。逆序数:1≤i<j≤n 并且满足ai>aj,就是一对逆序数。
思路:由于是相邻位置交换,交换一次最多减少一对逆序数,那么只要将初始的逆序数对数求出再减去k即可,若减完k后的结果小于0,那么输出0。
对于找逆序数,可以采用归并排序的方法。
原理:
如下图,因为归并前的两段数组分别都是有序的,假设有两段要归并的数组,t表示临时数组的下标,且t初始为i,比如在归并时第5位被放在了临时数组中的第2位,那么说明第5位之前有(5-2)=3个数比第5位大,即存在3对逆序数。继续归并,只要右端数组被归入了临时数组,那么cnt+=j-t,一直归并即可求出这两段数组中的逆序数对数。
下面是AC代码:
#include <bits/stdc++.h>
using namespace std;
int a[100005], temp[100005];
long long cnt = 0;
void Merge(int s, int m, int e)
{
int i = s, j = m + 1, t = s;
while (i <= m && j <= e)
{
if (a[i] <= a[j])//遇到相同的时候优先归并左侧的,因为左侧的原本就在前面
temp[t] = a[i++];
else
{
temp[t] = a[j];
cnt += j - t;
++j;
}
++t;
}
while (i <= m)
temp[t++] = a[i++];
while (s < j)//未归并的右侧不需要交换位置
{
a[s] = temp[s];
s++;
}
}
void Mergesort(int s, int e)
{
if (s >= e)
return;
int m = (s + e) / 2;
Mergesort(s, m);
Mergesort(m + 1, e);
Merge(s, m, e);
}
int main()
{
int m;
while (cin >> m)
{
for (int i = 1; i <= m; i++)
cin >> a[i];
Mergesort(1, m);
cout << cnt << endl;
}
return 0;
}