Loading

学校训练赛的一些题解

第二十一届宁波大学程序设计竞赛(重现赛链接

C 游戏开发部的小游戏 (C)

赛时并没有写出来,果然dp还得多练)

将所有石头视为容量为 \(n\) 的背包,每堆石头的数量即背包中物品的质量,对于 \(a_i \leq f_i\leq b_i\),由于 \(f_i\) 最终取值唯一,可当作分组背包处理。将大小为 \(i\)\(t\) 组石子装入剩余容量为 \(j - i\times t\) 的背包,由组合数公式,\(dp[j]\) 方案总数增加 \(dp[j - i\times t] \times {{n - j + i\times t}\choose i\times t}\times (i\times t)! / (i!)^t/(t!)\).

G 黑天鹅的记忆解析 (G)

又是dp题,首先排除 \(s\) 的前 \(m\) 个元素无法组成 \(t\) 的显然不合法情况,设 \(dp[i][j][k]\) 表示考虑到 \(s\) 的第 \(i\) 位、\(t\)\(j\)\(k\) 位已经匹配完成的情况,\(s_i = t_j\) 时即可从 \(j\)\(k\) 端点转移,复杂度 \(O(m^3)\).

    for(int i = 0; i < m; i++) {
        for(int j = 0; j < m; j++) {
            if(s[i] == t[j]) {
                for(int k = 0; k < j; k++) {
                    dp[i + 1][k][j] += dp[i][k][j - 1];
                }
                for(int k = j + 1; k < m; k++) {
                    dp[i + 1][j][k] += dp[i][j + 1][k];
                }
                dp[i + 1][j][j] += 2;
            }
        }
    }
    printf("%lld", dp[m][0][m - 1]);

另有:xht说可以暴力dfs,由于每次只能将字符放在开头或结尾处,状态不会超过 \(2^{20}\) 种,想了想挺有道理的,太有实力了)

I 小 Y.的魔法书 (I)

\(dp[i][j][k]\) 表示目前考虑到 \(t\) 的第 \(i\) 位、\(s\) 的第 \(j\) 位(怎么和上题有某种类似之处),待匹配的左括号数量为 \(k\) 的方案数。数据范围允许 \(n^2m\) 暴力转移,但不同的匹配过程可能得到相同结果,可以规定额外加入字符时 \(s'\) 不等于 \(s_j\),避免重复情况出现。

    dp[0][0][0] = 1;
    for(int i = 1; i <= n; i++) {
        for(int j = 0; j <= min(i, m); j++) {
            for(int k = 0; k <= i; k++) {
                if(j) {
                    if(s[j] == '(') {
                        if(k) add(dp[i][j][k], dp[i - 1][j - 1][k - 1]); // add取模加法
                        if(k < i) add(dp[i][j][k], dp[i - 1][j][k + 1]);
                        add(dp[i][j][k], dp[i - 1][j][k] * 26 % mo);
                    }
                    else if(s[j] == ')') {
                        if(k < i) add(dp[i][j][k], dp[i - 1][j - 1][k + 1]);
                        if(k) add(dp[i][j][k], dp[i - 1][j][k - 1]);
                        add(dp[i][j][k], dp[i - 1][j][k] * 26 % mo);
                    }
                    else {
                        if(k) add(dp[i][j][k], dp[i - 1][j][k - 1]);
                        if(k < i) add(dp[i][j][k], dp[i - 1][j][k + 1]);
                        add(dp[i][j][k], dp[i - 1][j - 1][k]);
                        add(dp[i][j][k], dp[i - 1][j][k] * 25 % mo);
                    }
                } else {
                    if(k < i) add(dp[i][j][k], dp[i - 1][j][k + 1]);
                    if(k) add(dp[i][j][k], dp[i - 1][j][k - 1]);
                    add(dp[i][j][k], dp[i - 1][j][k] * 26 % mo);
                }
            }
        }
    }
    printf("%lld\n", dp[n][m][0]);

K 五彩斑斓的世界 (K)

若某种颜色出现次数多于4,两两相连后一定会出现交点,可直接判断Yes输出;对于 \(cnt \leq 3\) 的情况,每种颜色的连线将多边形分成2或3个区间,随机生成哈希值作为不同区间的权值,使用线段树区间修改权值、单点查询相同颜色顶点的权值,若权值不相等,则说明该连线至少跨越一个区间,即存在相交情况。

ll val[N * 4], lz[N * 4];
void build(int i, int l, int r) {
    val[i] = lz[i] = 0;
    if(l >= r) return;
    int mid = (l + r) / 2;
    build(i * 2, l, mid);
    build(i * 2 + 1, mid + 1, r);
}
void pushdown(int i) {
    if(lz[i]) {
        val[i * 2] ^= lz[i];
        val[i * 2 + 1] ^= lz[i];
        lz[i * 2] ^= lz[i];
        lz[i * 2 + 1] ^= lz[i];
        lz[i] = 0;
    }
}
void modify(int i, int l, int r, int ql, int qr, ll d) {
    if(ql <= l && qr >= r) {
        val[i] ^= d;
        lz[i] ^= d;
        return;
    }
    pushdown(i);
    int mid = (l + r) / 2;
    if(ql <= mid) modify(i * 2, l, mid, ql, qr, d);
    if(qr > mid) modify(i * 2 + 1, mid + 1, r, ql, qr, d);
}
ll query(int i, int l, int r, int q) {
    if(l == r) return val[i];
    pushdown(i);
    int mid = (l + r) / 2;
    if(q <= mid) return query(i * 2, l, mid, q);
    return query(i * 2 + 1, mid + 1, r, q);
}

由于维护的有效值为单点权值,甚至不需要pushup操作,非常的好写。

2023四川大学“腾讯杯”新生赛(同步赛) (重现赛链接

D 小球染色 (D)

赛时没过这题,结合同学的AC代码想了下,忽然发现好简单。。。设 \(dp_i\) 表示对前 \(i\) 个小球合法染色的方案,当 \(i < k\) 时,\(dp_i = dp_{i - 1}\times c\)\(i \geq k\) 时需减去不合法情况,考虑在 \(i - k\) 个合法位置之后加入 \(k\) 个相同颜色的小球,使 \(c_{i - k} \neq c_i\) 以确保不合法情况不被算重,即 \(dp_i = dp_{i - 1}\times c -dp_{i - k} \times (c - 1)\);特别的,对于 \(i = k\)\(dp_i = dp_{i - 1}\times c -dp_{i - k} \times c\). 队友还给了另一种思路,从 \(i - k + 1\)\(i - 1\) 填补相同颜色的小球至 \(i\),有 \(dp_i =(c - 1)\times \sum\limits_{j = i - k + 1}^{i - 1} dp_j\),同样通过 \(c_j \neq c_i\) 做到不重不漏。

posted @ 2024-08-31 19:44  Aderose_yr  阅读(14)  评论(0编辑  收藏  举报