UOJ346

[题目链接]

https://uoj.ac/problem/346

[题解]

首先定义每个位置的值 \(val_{i} = min\{w\}\) , 也就是覆盖这个位置的 \(w\) 值最小值。 这样 , 最终这个位置填的权值是不能超过 \(val\) 的。

注意到每种权值互相独立 , 不妨分别计算将方案数相乘。

对于每种权值 , 考虑动态规划。

\(dp_{i , j}\) 表示前 \(i\) 个区间 , 上次放置在第 \(j\) 个区间的方案数。 这样只需考虑当前这个区间选 / 不选点转移即可。

时间复杂度 : \(O(Q ^ 3)\)

[代码]

#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 = 2005, mod = 998244353;

set < int > st;
int n, q, A, l[MN], r[MN], w[MN], s[MN], t[MN], dp[MN][MN], mn[MN], mx[MN], len;

inline void inc(int &x, int y) {
    x = x + y < mod ? x + y : x + y - mod;
}
inline void chkmin(int &x, int y) {
    x = min(x, y);
}
inline void chkmax(int &x, int y) {
    x = max(x, y);
}
inline int qPow(int a, int b) {
    int c = 1;

    for (; b; b >>= 1, a = 1ll * a * a % mod)
        if (b & 1)
            c = 1ll * c * a % mod;

    return c;
}
inline int calc(int now) {
    int tot = 0;

    for (int i = 1; i <= len; ++i)
        if (mn[i] == now)
            t[++tot] = i;

    if (!tot)
        return -1;

    for (int i = 1; i <= tot; ++i)
        mx[i] = 0;

    for (int i = 1; i <= q; ++i)
        if (w[i] == now) {
            int L = lower_bound(t + 1, t + 1 + tot, l[i]) - t,
                R = lower_bound(t + 1, t + 1 + tot, r[i]) - t - 1;
            chkmax(mx[R], L);
        }

    dp[0][0] = 1;

    for (int i = 1; i <= tot; ++i) {
        dp[i][i] = 0;
        int choose0 = qPow(now - 1, s[t[i] + 1] - s[t[i]]);
        int choose1 = qPow(now, s[t[i] + 1] - s[t[i]]);

        for (int j = 0; j < i; ++j) {
            if (j >= mx[i])
                dp[i][j] = 1ll * dp[i - 1][j] * choose0 % mod;
            else
                dp[i][j] = 0;

            inc(dp[i][i], 1ll * dp[i - 1][j] * ((choose1 + mod - choose0) % mod) % mod);
        }
    }

    int res = 0;

    for (int i = 0; i <= tot; ++i)
        inc(res, dp[tot][i]);

    return res;
}
inline void solve() {
    st.clear();
    scanf("%d%d%d", &n, &q, &A);
    s[len = 1] = 1;

    for (int i = 1; i <= q; ++i) {
        scanf("%d%d%d", &l[i], &r[i], &w[i]), ++r[i];
        s[++len] = l[i], s[++len] = r[i], st.insert(w[i]);
    }

    s[++len] = n + 1, sort(s + 1, s + 1 + len);
    len = unique(s + 1, s + 1 + len) - s - 1;

    for (int i = 1; i <= len; ++i)
        mn[i] = 1 + A;

    for (int i = 1; i <= q; ++i) {
        l[i] = lower_bound(s + 1, s + 1 + len, l[i]) - s;
        r[i] = lower_bound(s + 1, s + 1 + len, r[i]) - s;

        for (int j = l[i]; j < r[i]; ++j)
            chkmin(mn[j], w[i]);
    }

    int res = 1, x;

    for (set < int > :: iterator it = st.begin(); it != st.end(); ++it) {
        if (~(x = calc(*it)))
            res = 1ll * res * x % mod;
        else {
            puts("0");
            return;
        }
    }

    for (int i = 1; i < len; ++i)
        if (mn[i] == A + 1)
            res = 1ll * res * qPow(A, s[i + 1] - s[i]) % mod;

    printf("%d\n", res);
}
int main() {

    int T;
    scanf("%d", &T);

    while (T--)
        solve();

    return 0;
}
posted @ 2020-11-24 12:41  evenbao  阅读(89)  评论(0编辑  收藏  举报