学校训练赛的一些题解
第二十一届宁波大学程序设计竞赛(重现赛链接)#
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\) 做到不重不漏。
作者:Aderose_yr
出处:https://www.cnblogs.com/meowqwq/p/18389428
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
喵喵喵)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现