zoukankan      html  css  js  c++  java
  • [WC2021] 表达式求值

    [题目链接]

    https://loj.ac/p/3463

    [题解]

    首先让我们解决一个简单的问题 :

    注意到 (K) 很小 , 那么不妨维护 (f_{i , S}) 表示 (i) 号生物的每个位置是否都比 (S) 中每个元素的值大。

    (bitset) 维护 (f) , 查询时 , 从大到小枚举值即可。

    时间复杂度 : (O(frac{Q2 ^ {K}}{w}))

    解决这个问题的关键是 : 每个位置的值都是由 (K) 个初始数组中的元素得到的 , 而 (K) 又很小 , 因此可以通过压缩状态之类的方法求解。

    回到本题 , 首先不妨建出表达式树。这是一棵高度为 (O(N)) 的树 , 叶子节点维护的是位置 , 而非叶节点则为操作。( 详见 [代码] )

    (f_{u , S}) 表示 (u) 节点的值严格大于 (S) 中每个数的方案数。转移只需分别讨论两个儿子节点的情况。

    回答询问时进行容斥即可。

    时间复杂度 (O(N2 ^ {M}))

    [代码]

    #include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long LL;
    
    #define rep(i , l , r) for (int i = (l); i < (r); ++i)
    
    const int MN = 5e4 + 5, mod = 1e9 + 7;
    
    typedef pair < int, int > pii;
    #define mp make_pair
    
    int N, M, cnt, top, len, stk[MN], pre[MN], f[MN][2], g[1 << 12], a[12][MN], size,
        val[MN], child[MN][2];
    char s[MN];
    
    inline void inc(int &x, int y) {
        x = x + y < mod ? x + y : x + y - mod;
    }
    inline void dec(int &x, int y) {
        x = x - y >= 0 ? x - y : x - y + mod;
    }
    
    inline int get(int x) {
        if (s[x] == '<')
            return -1;
    
        if (s[x] == '>')
            return -2;
    
        return -3;
    }
    inline int build(int l, int r) {
        int cur = ++size;
    
        if (s[r] == ')' && pre[r] == l)
            ++l, --r;
    
        if (l == r)
            return val[cur] = s[l] - '0', cur;
    
        if (s[r] == ')') {
            val[cur] = get(pre[r] - 1);
            child[cur][0] = build(l, pre[r] - 2);
            child[cur][1] = build(pre[r], r);
        } else {
            val[cur] = get(r - 1);
            child[cur][0] = build(l, r - 2), child[cur][1] = build(r, r);
        }
    
        return cur;
    }
    
    int main() {
    
        scanf("%d%d", &N, &M);
    
        for (int i = 0; i < M; ++i)
            for (int j = 1; j <= N; ++j)
                scanf("%d", &a[i][j]);
    
        scanf("%s", s + 1);
        len = strlen(s + 1);
    
        for (int i = 1; i <= len; ++i)
            if (s[i] == '(')
                stk[++top] = i;
            else if (s[i] == ')')
                pre[i] = stk[top--];
    
        build(1, len);
    
        for (int s = 0; s < (1 << M); ++s) {
            for (int u = size; u >= 1; --u) {
                f[u][0] = f[u][1] = 0;
    
                if (val[u] >= 0)
                    f[u][s >> val[u] & 1] = 1;
                else {
                    if (val[u] != -2) {
                        inc(f[u][0], 1ll * (f[child[u][0]][0] + f[child[u][0]][1]) * (f[child[u][1]][0] + f[child[u][1]][1]) % mod);
                        dec(f[u][0], 1ll * f[child[u][0]][1] * f[child[u][1]][1] % mod);
                        inc(f[u][1], 1ll * f[child[u][0]][1] * f[child[u][1]][1] % mod);
                    }
    
                    if (val[u] != -1) {
                        inc(f[u][1], 1ll * (f[child[u][0]][0] + f[child[u][0]][1]) * (f[child[u][1]][0] + f[child[u][1]][1]) % mod);
                        dec(f[u][1], 1ll * f[child[u][0]][0] * f[child[u][1]][0] % mod);
                        inc(f[u][0], 1ll * f[child[u][0]][0] * f[child[u][1]][0] % mod);
                    }
                }
            }
    
            g[s] = f[1][0];
        }
    
        int ans = 0;
    
        for (int i = 1; i <= N; ++i) {
            vector < pii > vec;
    
            for (int j = 0; j < M; ++j)
                vec.emplace_back(mp(a[j][i], j));
    
            sort(vec.begin(), vec.end());
            int s = (1 << M) - 1;
    
            for (int j = 0; j < M; ++j) {
                int ns = s ^ (1 << vec[j].second);
                inc(ans, 1ll * (g[ns] + mod - g[s]) * vec[j].first % mod);
                s = ns;
            }
        }
    
        printf("%d
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    二维数组中的查找
    排序算法——冒泡、选择、插入
    排序算法——快速、归并
    最小的K个数
    重建二叉树
    反转链表
    LeetCode 278 第一个错误的版本
    LeetCode 929 独特的电子邮件地址
    LeetCode 38 报数
    模型参数初始化
  • 原文地址:https://www.cnblogs.com/evenbao/p/14441727.html
Copyright © 2011-2022 走看看