zoukankan      html  css  js  c++  java
  • 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
    ", res);
    }
    int main() {
    
        int T;
        scanf("%d", &T);
    
        while (T--)
            solve();
    
        return 0;
    }
  • 相关阅读:
    理解C语言中指针常量和常量指针区别!不要再搞混了~
    哪座城市可以安放程序员的灵魂,一线城市与二三线城市该如何择别?
    Linux 之父如何定义 "Linux" !主要想让黑客、计算机学生使用,学习和享受!
    程序员的凡尔赛文学!作为低调人群的程序员,“凡”起来又是怎样的一番景象呢?
    40个Java集合面试问题和答案
    从关系型数据库到非关系型数据库
    redis安装报错
    redis简介
    不满足依赖关系
    EL表达式中引用隐式变量
  • 原文地址:https://www.cnblogs.com/evenbao/p/14029624.html
Copyright © 2011-2022 走看看