Inversion
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
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
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
问题分析
利用归并排序,在合并的时候的时候求出逆序数对数。
假设我们用笨办法冒泡排序去看交换的次数,明显是会超时的。所以我们在这里采用分治思想(nlogn):
①将数组分成两半,分别去求左边和右边的逆序数。
②再加上从左边取一个数与右边取一个数构成的逆序数。
第二步的关键是左边和右边都是排好序的,假如都是从大到小排序的,我们只需要左右半边扫一遍就可以找出来了。
好,下面上code(^_^)
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5;
typedef long long ll;
ll ans;
void merge(int s,int m, int e, int a[],int temp[])//合并过程中计算逆序数
{
int p1 = s, p2 = m+1, k = 0;
while(p1<=m&&p2<=e)
{
if(a[p1]>a[p2]){ //如果a[p1]>a[p2],那在前半部分比a[p1]大的数都满足逆序数
temp[k++] = a[p2++];
ans+=m-p1+1;
}
else temp[k++] = a[p1++];
}
//将剩余未拷贝完的拷贝到临时数组
while(p1<=m) temp[k++] = a[p1++];
while(p2<=e) temp[k++] = a[p2++];
for(int i = 0; i < e-s+1; i++) //再拷贝到原数组
a[s+i] = temp[i];
}
void mergeSort(int s,int e,int a[],int temp[])
{
if(s<e)
{
int m = s+(e-s)/2;
//分治
mergeSort(s,m,a,temp);
mergeSort(m+1,e,a,temp);
//归并
merge(s,m,e,a,temp);
}
}
int main()
{
int n,k,a[N],temp[N];
while(~scanf("%d%d",&n,&k))
{
ans = 0;
for(int i = 0; i < n; i++)
scanf("%d",&a[i]);
mergeSort(0,n-1,a,temp);
if(ans>=k)
cout<<ans-k<<endl;
else
printf("0\n");
}
return 0;
}