前言
下午hdu oj又再次登不上了,终于在晚上又能登上了,来一波归排~
一、题目
二、题目分析
一道以归并排序为板子的题,需讨论以下两种情况(设有cnt个逆序对):
1.cnt<=k,即逆序对的数量不大于最大交换次数k,所以进行了k次交换后,最少的逆序对数为0;
2.cnt>k,让k次交换都发生在逆序的相邻数上,则剩余逆序对数为cnt-k;
此求取逆序对的程序完全套用了归并排序的模板,相比之下多了一个cnt+=mid-i+1;
三、代码
归并排序思想:采用分治法进行排序,将序列分成一个个小序列1,再将排序后的小序列合并成一个较大序列…最终得到排序好的序列。
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
//板子:计算逆序对,即在进行归并排序时判断记录,cnt+=mid-i+1;
const int maxn=100005;
typedef long long ll;
ll a[maxn],b[maxn],cnt;
void Merge(ll l,ll mid,ll r){
ll i=l,j=mid+1,t=0;//定义i,j两个指针用于归并排序
while(i<=mid&&j<=r){
if(a[i]>a[j]){//前大于后------出现逆序对
cnt+=mid-i+1;//计算逆序对个数
b[t++]=a[j++];//合并,执行顺序:先b[t]=a[j],后t++,j++;
}
else b[t++]=a[i++];//
}
//两个while语句只会执行其中一个或都不执行
while(i<=mid) b[t++]=a[i++];//当左边子序列经过上边操作后有剩余,则全复制到b中
while(j<=r) b[t++]=a[j++];//同上;
for(i=0;i<t;i++){//最后将b中元素全返回给a
a[l+i]=b[i];
}
}
void Mergesort(ll l,ll r){//递归实现归排
if(l<r){
ll mid=(l+r)/2;
Mergesort(l,mid);//左
Mergesort(mid+1,r);//右
Merge(l,mid,r);
}
}
int main(){
ll n,k;
while(cin>>n>>k){
cnt=0;
for(ll i=0;i<n;i++)
cin>>a[i];
Mergesort(0,n-1);
if(cnt<=k)cout<<"0"<<endl;
else printf("%I64d\n",cnt-k);
}
}