AtCoder DP Practice

众所周知,AtCoder 有一场极 educational 的 DP Contest

A

裸的线性 DP,设 \(dp_i\) 表示跳到第 \(i\) 个格子的最小费用,显然有转移:

\[dp_{i} = \min(dp_{i - 1} + |h_i - h_{i - 1}|, dp_{i - 2} + |h_i - h_{i - 2}|) \]

边界为 \(dp_1 = 0, dp_2 = |h_1 - h_2|\)

B

裸的线性 DP,设 \(dp_i\) 表示跳到第 \(i\) 个格子的最小费用,显然有转移:

\[dp_{i} = \min_{1 \leq j \lt i} dp_j + |h_i - h_j| \]

边界为 \(dp_1 = 0\)

C

裸的线性 DP,设 \(f_{i, 0}, f_{i, 1}, f_{i, 2}\) 分别为第 \(i\) 天选择 \(a, b, c\) 活动的最大值,显然有转移:

\[\begin{cases} dp_{i, 0} = \min(dp_{i - 1, 1}, dp_{i - 1, 2}) + a_i \\ dp_{i, 1} = \min(dp_{i - 1, 0}, dp_{i - 1, 2}) + b_i \\ dp_{i, 2} = \min(dp_{i - 1, 0}, dp_{i - 1, 1}) + c_i \\ \end{cases} \]

答案为 \(\min(dp_{n, 0}, dp_{n, 1}, dp_{n, 2})\)

D

裸的 01 背包,二维太裸了,直接滚动数组。设 \(dp_i\) 表示处理到当前物品时背包容量为 \(i\) 的最大价值,得:

\[dp_j = \max(dp_j, dp_{j - w_i} + v_i) \]

注意要从 \(w \to w_i\) 枚举才能控制每个物品进入 \(1\) 次,否则就是完全背包。

E

传统 01 背包装肯定要爆的,但是注意到虽然 \(w_i\) 大,但是 \(v_i\) 小,可以不是很自然地想到交换价值和体积,即设 \(dp_{i, j}\) 表示考虑前 \(i\) 个物品,达到 \(j\) 价值所需的最小体积,得到类似 01 背包的转移:

\[dp_{j} = \max(dp_j, dp_{j - v_i} + w_i) \]

维护总价值,从大到小枚举总价值,找到第一个满足 \(dp_i \leq m\)\(dp\) 值输出其 \(i\) 即可。

F

暴力 LCS 转移是一个 DP 初心者也可以轻松设计出来的状态,设 \(dp_{i, j}\) 表示考虑 \(s\) 的前 \(i\) 个字符和 \(t\) 的前 \(j\) 个字符的 LCS 长度,则有转移:

\[dp_{i, j} = \begin{cases} dp_{i - 1, j - 1} + 1 (s_i = t_j) \\ \max(dp_{i, j - 1}, dp_{i - 1, j}) (s_i \neq t_j) \\ \end{cases} \]

通过判断转移至 \(i, j\) 是否增加来保存最优路径。

G

优美的有向无环图,每个点跑一次 DP,\(O(n)\) 解决问题。

H

简单的“数字三角形”类的 DP,设 \(dp_{i, j}\) 表示走到 \((i, j)\) 的方案数,显然有转移:

\[dp_{i, j} = dp_{i - 1, j} + dp_{i, j - 1} \]

corner case 处理可以聪明一点,我们在 \(dp_{0, 1}/dp_{1, 0}\) 设为 \(1\),然后 \(i = 1 \to h, j = 1 \to w\) 遍历直接转移就能少掉边界的讨论。

I

概率 DP,还是那句话,没什么头绪就考虑把答案作为 DP 状态。

\(dp_{i, j}\) 表示前 \(i\) 个硬币中 \(j\) 个正面朝上的概率,转移算算就推出来了(其中 \(p_i\) 为题目给定的正面朝上的概率):

反面朝上的概率为:

\[dp_{i, 0} = dp_{i - 1, 0} \times (1 - p_i) \]

正面朝上的处理也挺简单:

\[dp_{i, j} = \left( dp_{i - 1, j - 1} \times p_i \right) + \left( dp_{i - 1, j} \times (1 - p_i) \right) \]

注意到可以滚掉 1 维,但是没必要。

J

写一次忘一次的期望 DP,可以看看 这个 (doge,当时我怎么写明白的,太牛了

K

一眼的结论:若剩余 \(0\) 个石子则当前游戏者必败。

\(dp_i\) 为剩余 \(i\) 个石头时的胜负情况,只要能转移到一个必败状态那就能 win 了,暴力 for 枚举就能做。

L

类似区间 DP,少了断点枚举。设 \(dp_{l, r}\) 表示当前游戏方在 \(l, r\) 内能取到的最大值,则有转移:

\[dp_{l, r} = \max \left( \sum_{l}^{r} - dp_{l + 1, r}, \sum_{l}^{r} - dp{l, r - 1} \right) \]

corner case 显然是 \(dp_{i, i} = a_i\)。维护前缀和 \(O(1)\) 转移即可。

M

前缀和优化,设 \(dp_{i, j}\) 表示前 \(i\) 个数加起来和为 \(j\) 的情况,通过枚举最后一个数显然有转移:

\[dp_{i, j} = \sum_{x = 0}^{a_i} dp_{i - 1, j - x} \]

边界为 \(dp_{1, j} = [j \leq a_i]\)

暴力转移显然 T,但是这个东西可以上个前缀和优化:

记:

\[S_{i, j} = \sum_{x = 0}^{j} dp_{i, j} \]

可以改写转移了:

\[\begin{aligned} dp_{i, j} &= S_{i - 1, j} - S_{i - 1, j - a_i - 1} \\ S_{i, j} &= S_{i, j - 1} + dp_{i, j} \\ \end{aligned} \]

N

只能合并相邻项的石子合并,设 \(dp_{i, j}\) 表示合并 \(a_i \sim a_j\) 的最小代价,则有转移:

\[dp_{i, j} = \min_{i \leq k \leq j} \left( dp_{i, j}, dp_{i, k} + \sum_{p = i}^{j} a_p \right) \]

边界就比较常规了,初值为 \(inf\),其中 \(dp_{i, i} = 0\)

O

状压 DP,考虑能转移的条件:

  1. 当前集合中男女生相容

  2. 当前男女生尚未匹配

\(dp_{i, j}\)\(i\) 个男生和女生构成的集合 \(j\) 的匹配数量,设 \(S_j\) 表示集合中已经有的女生情况,显然枚举 \(i\) 的过程中需要保证 \(S_j = i\),然后枚举另一个女生满足上述两个条件。写个裸转移:

\[dp_{i, j} = \sum_{k \in j, a_{i, k} = 1} dp_{i - 1, j - k} \]

P

Easy 树形 DP。类似没有上司的舞会,设树根为 \(1\),当前节点为 \(u\),设 \(dp_{u, 0}/dp_{u, 1}\) 表示当前节点染白/黑。则根据乘法原理显然有转移:

\[\begin{aligned} dp_{u, 0} &= \prod_{v \in u} \left( dp_{v, 0} + dp_{v, 1} \right) \\ dp_{u, 1} &= \prod_{v \in u} dp_{v, 0} \end{aligned} \]

Q

是不是挺典的。设 \(dp_i\) 为前 \(i\) 朵花满足“高度单调递增”的情况下权值的最大值,转移为:

\[dp_{i} = \max_{j = 1}^{i - 1} \{ dp_j \mid h_j \lt h_i \} + a_i \]

这个裸的是 \(O(n^2)\) 的,但是上个数据结构比如 Fenwick/ Segtree 来查 \(dp_1 \sim dp_{i - 1}\)\(\max\) 就能拿下了。

R

我们都会有一个 naive 的第一想法:设 \(dp_{i, j, k}\) 表示从 \(i\)\(k\) 步到 \(j\) 的方案数,这个转移非常 easy,但是是 \(O(n^3 k)\)

考虑设 \(dp_{i, j}^{k}\) 表示从 \(i\)\(k\) 步到 \(j\) 的方案数,然后我们通过 Floyd 枚举中转点的思路就有转移:

\[dp_{i, j}^{k} = \sum_{p = 1}^{n} dp_{i, p}^{1} \times dp_{p, j}^{k - 1} \]

然后这个东西是可以上矩乘优化的,答案即为矩阵的 \(k\) 次方中所有数的和,复杂度压进了 \(O(n^3 \log k)\)

posted @ 2024-12-17 19:15  revkiru  阅读(3)  评论(0编辑  收藏  举报