版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sugarbliss/article/details/85165867
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4911
题意:最多可以交换K次,就最小逆序对数。
思路:逆序数定理,当逆序对数大于0时,若ai<ai+1,那么交换后逆序对数+1,反之-1。所以只需要求一下逆序数的个数就行了。逆序数的求解可以用树状数组。我们用树状数组维护某个区间中数字出现的个数,将原数据按其原来顺序插入树状数组,第i个数字插入的方式为将树状数组的第a[i]位设为1,同时更新覆盖到它的父区间,sum(a[i])可求得[1, a[i]]的区间和,这恰好代表第i个数字前小于等于它的个数,等于的只可能是自身,故小于它的有sum(a[i])-1个,那么大于它的显然就有i-1-(sum(a[i])-1) = i-sum(a[i])个。
要知道树状数组的长度是数据范围,由于数据比较大,所以要离散化。注意开long long。
#include <bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define pii pair<int,int>
#define ll long long
const int maxn = 1e5+5;
int n, k;
bool cmp(pii a, pii b)
{
return a.first < b.first;
}
struct BIT
{
int n, c[maxn*5];
void init(int n)
{
this -> n = n;
mem(c,0);
}
void add(int p, int x)
{
for(int i = p; i <= n; i += i&-i)
c[i] += x;
}
ll sum(int p)
{
ll ans = 0;
for(int i = p; i >= 1; i -= i&-i)
ans += c[i];
return ans;
}
}bit;
int main()
{
while(~scanf("%d%d", &n,&k))
{
bit.init(n); int x; ll cnt = 0;
vector <pii> v; map <ll,ll> mp;
v.clear(); mp.clear();
for(int i = 0; i < n; i++)
{
scanf("%d",&x);
v.push_back({x,i+1});
}
sort(v.begin(),v.end(),cmp);
int c = 1; mp[v[0].second] = c;
for(int i = 1; i <= n; i++)
{
if(v[i].first == v[i-1].first) mp[v[i].second] = c;
else mp[v[i].second] = ++c;
}
for(int i = 1; i <= n; i++)
{
bit.add(mp[i],1);
cnt += i - bit.sum(mp[i]);
}
printf("%lld\n",max(cnt-k,0LL));
}
}