首页 > 其他 > 详细

「BZOJ 1831」「AHOI 2008」逆序对「贪心」

时间:2019-02-09 19:48:27      阅读:185      评论:0      收藏:0      [点我收藏+]

题意

给定一个长度为\(n\),值域为\([1,k]\),某些位置不确定的数组,求最小的逆序对。\(n\leq 10^4, k \leq 100\)

题解

这题有人用前缀和优化\(dp\)过了,但是这里还是讲一种逐一填的做法

首先证明:填进去的数一定是单调不减的,换句话说不构成逆序对。证明很简单,因为假设两个填进去的数构成的逆序对,交换这两个数,不影响其他逆序对,而逆序对数\(-1\)

所以我们只要考虑已经填好的数。每次找到一个贡献最小的\(k\)填就行了。

我用树状数组维护了一下,实际上直接数组也可以。

#include <algorithm>
#include <cstdio>
using namespace std;

const int N = 1e4 + 10;

int n, k, a[N], bit[2][N];

void add(int z, int x, int y) {
    for(; x <= k; x += x & (-x)) bit[z][x] += y;
}
int qry(int z, int x) {
    int ans = 0;
    for(; x >= 1; x &= x - 1) ans += bit[z][x];
    return ans;
}

int main() {
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= n; i ++) {
        scanf("%d", a + i);
        if(~ a[i]) add(1, a[i], 1);
    }
    int ans = 0;
    for(int i = 1; i <= n; i ++) {
        if(a[i] == -1) {
            int x = 1, y = n << 1;
            for(int j = 1; j <= k; j ++) {
                int s = qry(0, k) - qry(0, j) + qry(1, j - 1);
                if(s < y) y = s, x = j;
            }
            a[i] = x;
            add(0, a[i], 1);
        } else add(0, a[i], 1), add(1, a[i], -1);
        ans += qry(0, k) - qry(0, a[i]);
    }
    printf("%d\n", ans);
    return 0;
}

「BZOJ 1831」「AHOI 2008」逆序对「贪心」

原文:https://www.cnblogs.com/hongzy/p/10357877.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!