2018多校赛第二场 Swaps and Inversions(树状数组求逆序对+离散化)

题意

给定一个数组a,每存在一个逆序对需要付出x的代价,每交换两个相邻的元素需要付出y的代价。
求最少付出代价。

解题

模拟一下交换操作,会发现将一个无序的数组变成一个不降序数组所需操作次数恰好是数组中逆序对存在的个数。所以最小代价就是min(x,y)*逆序对的个数。

求逆序对的个数可以用归并排序或者本文所用的树状数组(个人觉得比较好写)。
数组值的范围比较大,所以需要离散化。所谓离散化,我的理解就是排个序然后用排序后的下标来表示这个值。
时间复杂度为O(nlogn).
这题还是比较简单的,就不赘述了。

AC代码


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
const ll maxn=2e5+7;
struct node
{
    ll v,num;
    bool operator<(const node &o)const{
        return v<o.v;
    }
}a[maxn];
ll tree[maxn];
ll b[maxn];
ll lowbit(ll x)
{
    return x&(-x);
}
ll getsum(ll i)
{
    ll ans=0;
    while(i>0)
    {
        ans+=tree[i];
        i-=lowbit(i);
    }
    return ans;
}
void add(ll i,ll v)
{
    while(i<maxn)
    {
        tree[i]+=v;
        i+=lowbit(i);
    }
}
int main()
{
    ll n,x,y,ans;

    while(~scanf("%lld%lld%lld",&n,&x,&y))
    {
        ans=0;
        for(ll i=1;i<=n;i++)
        {
            ll v;
            scanf("%lld",&v);
            a[i].v=v;
            a[i].num=i;
        }
        sort(a+1,a+1+n);
        ll cnt=0;
        b[a[1].num]=++cnt;
        for(ll i=2;i<=n;i++)
        {
            if(a[i].v==a[i-1].v)
                b[a[i].num]=cnt;
            else
                b[a[i].num]=++cnt;
        }
        memset(tree,0,sizeof(tree));
        for(ll i=n;i>=1;i--)
        {
            ll num=b[i];
            add(num,1);
            ans+=getsum(num-1);
        }
        ll z=min(x,y);
        printf("%lld\n",z*ans);
    }
    return 0;
}
/*
5 1 2
200000000 -12545545545 12 3559 6
*/

猜你喜欢

转载自blog.csdn.net/qq_37685156/article/details/81254278