[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\n", ans);
    return 0;
}
posted @ 2021-02-24 15:31  evenbao  阅读(105)  评论(0编辑  收藏  举报