HDU 6318 Swaps and Inversions(树状数组 + 离散化)

HDU - 6318

题意:给定一个整数序列,如果交换两个相邻数,花费y元,每消除一个逆序数需花费x元,其实x,y等效,学完线代就知道,每次交换两个相邻的数,逆序数必定改变,而我们必定向着逆序数减小的方向进行,所以我们每次花费x或者y元都可以使逆序数减小1,这样问题就转化为求序列的逆序数,最后结果乘上min(x, y)即可。

问题就在于序列中的数太大了,树状数组存不下,需要离散化一下

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
using namespace std;
int n, x, y;
struct node
{
    int cnt;
    long long num;
}a[100005];
long long c[100005];
int lowbit(int x)
{
    return x & (-x);
}
void update(int x)
{
    while(x <= 100005)
    {
        c[x] += 1;
        x += lowbit(x);
    }
}
int getsum(int x)
{
    int ans = 0;
    while(x > 0)
    {
        ans += c[x];
        x -= lowbit(x);
    }
    return ans;
}
bool cmp(node a, node b)
{
    if(a.num != b.num) return a.num < b.num;
    else return a.cnt < b.cnt;
}
int main()
{
    while(scanf("%d%d%d",&n,&x,&y) != EOF)
    {
        int cnt1 = 0;
        memset(c, 0, sizeof(c));
        for(int i = 1; i <= n; i ++)
        {
            scanf("%lld",&a[i].num);
            a[i].cnt = ++ cnt1;
        }
        sort(a + 1, a + 1 + n, cmp);
        long long ans = 0;
        for(int i = 1; i <= n; i ++)
        {
            update(a[i].cnt);
            ans += (i - getsum(a[i].cnt));
        }
        printf("%lld\n", ans * min(x, y));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41444888/article/details/81280779