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

题目链接

题意:有一个长度为n的乱序集合,如果一个子序列为逆序,你就要付x元,或者你可以选择修改一个相邻的数字,你就要付y元,问最少你要付多少钱。(其实你交换一个存在逆序的相邻数字就可以减少一个逆序数)

这题不知道是题目的意思太绕还是怎样,我看了很久硬是每看懂题目在讲什么,后来看了一下大佬们的代码和解释才知道,这不就是树状数组的入门题吗。。我。。。英语和语文阅读能力大概是没救了。。。

思路:就是算这个集合存在多少逆序数,最后的答案乘min(x,y)就可以了。(好像应该也可以用线段树做,不过这个就是数组数组的板子题)

AC代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;

typedef long long ll;
const int maxn = 1e5+10;
int c[maxn],a[maxn],b[maxn];
int n, x, y;

ll lowbit(int x){
    return x&(-x);
}

void add(int x,int y){
    for(int i = x; i <= n; i+=lowbit(i))
        c[i] += y;
}

ll query(int x){
    ll ans = 0;
    for(int i = x; i > 0; i-=lowbit(i))
        ans += c[i];
    return ans;
}

int main(){
    int i;
    while(scanf("%d%d%d",&n,&x,&y)!=EOF){
        memset(c, 0, sizeof(c));
        for(i = 1; i <= n; i++){
            scanf("%d",&a[i]);
            b[i] = a[i];
        }
        sort(b+1, b+1+n);
        ll ans = 0;
        for(i = n; i > 0; i--){      //这里要从n开始,因为可能存在相同的数字,把数字按原本位置从后往前插入树状数组,查看在它原本位置后面有多少个小于它的数,就存在多少逆序数
            int t = lower_bound(b+1, b+1+n, a[i])-b;    //找到第一个大于等于a[i]的数的位置,所以查询的时候要减1
            ans += query(t-1);
            add(t, 1);
        }
        printf("%lld\n",ans*min(x,y));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zhuyou_/article/details/81217522
今日推荐