HDU 4911 (树状数组求逆序数+离散化)

版权声明:本文为博主原创文章,未经博主允许不得转载。 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));
    }
}

猜你喜欢

转载自blog.csdn.net/sugarbliss/article/details/85165867
今日推荐