zoukankan      html  css  js  c++  java
  • 「BZOJ 1831」「AHOI 2008」逆序对「贪心」

    题意

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

    题解

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

    首先证明:填进去的数一定是单调不减的,换句话说不构成逆序对。证明很简单,因为假设在(i)(j)两处((i < j)),填进去的数构成逆序对,交换这(i, j),不影响([1, i - 1],[j + 1, n])的逆序对,对于([i + 1, j - 1])来说逆序对减少或不变,并且(i,j)构成的逆序对消失。

    所以我们只要考虑已经填好的数。每次找到一个贡献最小的(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
    ", ans);
        return 0;
    }
    
    
  • 相关阅读:
    Cookie操作
    C# 操作Cookie类
    面向对象之struct
    高薪程序员都避开了那些坑【安晓辉】
    [转]C#之反射
    [转]正则表达式相关:C# 抓取网页类(获取网页中所有信息)
    membership 在web.config中配置信息
    面向对象之virtual
    面向对象之多态
    JAVA面向对象 接口
  • 原文地址:https://www.cnblogs.com/hongzy/p/10357877.html
Copyright © 2011-2022 走看看