AtCoder DP Practice
众所周知,AtCoder 有一场极 educational 的 DP Contest。
A
裸的线性 DP,设 表示跳到第 个格子的最小费用,显然有转移:
边界为 。
B
裸的线性 DP,设 表示跳到第 个格子的最小费用,显然有转移:
边界为 。
C
裸的线性 DP,设 分别为第 天选择 活动的最大值,显然有转移:
答案为 。
D
裸的 01 背包,二维太裸了,直接滚动数组。设 表示处理到当前物品时背包容量为 的最大价值,得:
注意要从 枚举才能控制每个物品进入 次,否则就是完全背包。
E
传统 01 背包装肯定要爆的,但是注意到虽然 大,但是 小,可以不是很自然地想到交换价值和体积,即设 表示考虑前 个物品,达到 价值所需的最小体积,得到类似 01 背包的转移:
维护总价值,从大到小枚举总价值,找到第一个满足 的 值输出其 即可。
F
暴力 LCS 转移是一个 DP 初心者也可以轻松设计出来的状态,设 表示考虑 的前 个字符和 的前 个字符的 LCS 长度,则有转移:
通过判断转移至 是否增加来保存最优路径。
G
优美的有向无环图,每个点跑一次 DP, 解决问题。
H
简单的“数字三角形”类的 DP,设 表示走到 的方案数,显然有转移:
corner case 处理可以聪明一点,我们在 设为 ,然后 遍历直接转移就能少掉边界的讨论。
I
概率 DP,还是那句话,没什么头绪就考虑把答案作为 DP 状态。
设 表示前 个硬币中 个正面朝上的概率,转移算算就推出来了(其中 为题目给定的正面朝上的概率):
反面朝上的概率为:
正面朝上的处理也挺简单:
注意到可以滚掉 1 维,但是没必要。
J
写一次忘一次的期望 DP,可以看看 这个 (doge,当时我怎么写明白的,太牛了
K
一眼的结论:若剩余 个石子则当前游戏者必败。
设 为剩余 个石头时的胜负情况,只要能转移到一个必败状态那就能 win 了,暴力 for 枚举就能做。
L
类似区间 DP,少了断点枚举。设 表示当前游戏方在 内能取到的最大值,则有转移:
corner case 显然是 。维护前缀和 转移即可。
M
前缀和优化,设 表示前 个数加起来和为 的情况,通过枚举最后一个数显然有转移:
边界为 。
暴力转移显然 T,但是这个东西可以上个前缀和优化:
记:
可以改写转移了:
N
只能合并相邻项的石子合并,设 表示合并 的最小代价,则有转移:
边界就比较常规了,初值为 ,其中 。
O
状压 DP,考虑能转移的条件:
-
当前集合中男女生相容
-
当前男女生尚未匹配
设 为 个男生和女生构成的集合 的匹配数量,设 表示集合中已经有的女生情况,显然枚举 的过程中需要保证 ,然后枚举另一个女生满足上述两个条件。写个裸转移:
P
Easy 树形 DP。类似没有上司的舞会,设树根为 ,当前节点为 ,设 表示当前节点染白/黑。则根据乘法原理显然有转移:
Q
是不是挺典的。设 为前 朵花满足“高度单调递增”的情况下权值的最大值,转移为:
这个裸的是 的,但是上个数据结构比如 Fenwick/Segtree 来查 的 就能拿下了。
R
我们都会有一个 naive 的第一想法:设 表示从 走 步到 的方案数,这个转移非常 easy,但是是 。
考虑设 表示从 走 步到 的方案数,然后我们通过 Floyd 枚举中转点的思路就有转移:
然后这个东西是可以上矩乘优化的,答案即为矩阵的 次方中所有数的和,复杂度压进了 。
S
数位 DP,套公式:设 表示处理到第 位(从右往左),当前前缀 为 ,是否顶上界,记忆化:
int dfs(int u, int x, int lim) {
if (!u) { return (x == 0); }
if (~dp[u][x][lim]) { return dp[u][x][lim]; }
int ret = 0, mx = 9;
if (lim) { mx = num[u]; }
for (int i = 0; i <= mx; i++)
ret = (ret + dfs(u - 1, (x + i) % d, lim && (i == mx))) % P;
return dp[u][x][lim] = ret;
}
T
第一次一眼秒蓝题。
设 为前 个数填入 ,以 结尾的方案数。注意到对于一个序列的内部排列我们只关心相对顺序,而不是具体的值,在转移过程中,可以将前 个数中 的数 保证序列为排列,得到转移:
边界为 ,上个前缀和优化一下转移。
U
一眼状压,其实光读题也能猜到是状压了。设 为集合为 时的最大得分,考虑转移即为把集合 划分为 个子集,然后取其和,转移显然:
记忆化搜索处理,枚举个子集。
V
不懂什么叫“换根 DP”,考虑钦定树根为 ,设 为在 的子树中选( 必选)染色,所有点联通的方案数, 表示在 子树外选点,显然对于点 的答案即为 ,分别给出转移:
预处理每个子节点权值的前缀积和后缀积实现,人话就是跑两边 。
注: 表示有一种只有当前节点染色的方案。
W
套路题,把答案放到区间右端点来统计。设 表示在前 个位置中,最后一个 在 的最大分数,得到转移:
这个空间上可以滚动掉一维,但是时间复杂度还是 的,但是注意到对于 ,在 时,会于 中产生贡献,这样子问题就转化为了区间加。对于 操作显然也是线段树的基本操作之一,对于 数组维护一棵线段树即可。
X
显然是 01 背包,问题在于如何确定一个枚举顺序,也就是各个箱子的优先级。
考虑贪心,有一个技巧叫做 exchange arguments 用于证明贪心,在这个题,显然对于 的情况是要先考虑 的,那么交换一下项得到排序依据 。
然后 01 搞。
Y
在没看到 的范围之前以为是个傻子题,发现我是傻子。
考虑容斥。在一张没有障碍的地图内从 的方案为 (从 次选择中选择 次向下,其他向右),考虑有障碍的时候就要上容斥了,裸的肯定不行,令 为从 到 障碍,不经过其他障碍的方案数,我们将 设为第 个障碍就会很舒服,答案即为 。然后我们给出转移:
这是对的。
Z
斜率优化。裸转移显然:
转移 T 飞。
拆一下式子:
这个第一个括号只和 有关,最后一项是个常数项,抽离出一个一次函数:
求解 相当于求前 的一次函数在平面直角坐标系内经过 的最小值,嗯造李超树求解。
ーおわりー
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效