知识学报:DP(1)

不是题解不是教学!!!

10.16

ATcoder Educational DP Contest A

题目给了 \(n \leq 1e5\) 个点,每个点有一个权值。从第 \(i\) 个点可以跳到第 \(i + 1\) 或第 \(i + 2\) 个点,花费是两点权值之差。
那么每个点都转移到后面两个点,并取被转移点的最小值就行了,不再赘述。

10.20

ATcoder Educational DP Contest B

和上题类似,但是跳的点从只有 \(i + 1\)\(i + 2\) 变成了可以一直跳到 \(i + k\)\(k \leq 100\)\(n \times k\) 足够小,暴力转移即可

ATcoder Educational DP Contest C

\(n \leq 1e5\) 天,第 \(i\) 天可以从三种活动中选一个做,分别加 \(a_i\)\(b_i\)\(c_i\) 的幸福值,但第 \(i\) 天和第 \(i - 1\) 天的活动不能一样,问最大幸福值。
对于第 \(i\) 天,我们只关心第 \(i - 1\) 天做了什么活动以及做这个活动前面的最大幸福值,所以只存第 \(i\) 天的做第 \(j\) 种活动的最大幸福值,第 \(i + 1\) 天的做第 \(j\) 种活动的最大幸福值就是第 \(i\) 天的另外两种活动的最大幸福值加 \(j_{i + 1}\),最后输出第 \(n\) 天做任意活动的最大值即可。

ATcoder Educational DP Contest D

\(n \leq 100\) 个物品和一个最大容量为 \(W \leq 1e5\) 的背包,每个物品有重量 \(w_i \leq W\) 和价值 \(v_i \leq 1e9\),问最大能装价值多少的物品。
对于第 \(i\) 个物品,我们只关心前面所有情况可能构成的价值和重量对,而有效重量最大为 \(1e5\),所以可以维护对于前 \(i\) 个物品选择了重量 \(used\) 的情况的最高价值。转移的方式是从所有可以选择第 \(i\) 个物品的 \(used\) 选择该物品后,\(used + w_i\) 记录的最高价值和这个价值比较并更新为较大值。也就是 \(dp[used + w_i] = \min(dp[used + w_i], dp[used] + v_i)\)

ATcoder Educational DP Contest E

和上题类似,但 \(W \leq 1e9\)\(v_i \leq 1e3\)
我们关心的东西不变,但有效重量过大无法维护,考虑维护价值,记录选了前 \(i\) 个物品时总价值为 \(x\) 时最少的重量。对于第 \(i\) 个物品,选择一个可以选择的价值 \(x\),然后更新 \(x + v_i\),就是 \(dp[x + v_i] = \min(dp[x + v_i], dp[x] + w_i)\)。最后输出最大的选择重量小于 \(W\) 的价值。
注意要把 \(dp\) 数组都初始化为一个足够大的数。

ATcoder Educational DP Contest F

题目给两个长度为 \(n\)\(m\) 的字符串,问这两个串的最长公共子序列是什么,\(1 \leq n,m \leq 3000\)
先考虑最长公共子序列的长度,容易想到状态设计为 \(s1\) 中已经用到第 \(i\) 个,\(s2\) 中用到第 \(j\) 个时最长公共子序列为多少。状态转移就是如过 \(s1[i] = s2[j]\),那么 \(dp[i][j] = \max (dp[i - 1][j - 1] + 1, dp[i][j])\),否则 \(dp[i][j] = \max (dp[i - 1][j], dp[i][j - 1])\)
接下来考虑怎么得到具体的字符串,首先我们不能每次转移时带着整个字符串,否则时间复杂度会达到 \(O(n^3)\)。除了用指针之外,我们发现我们可以通过最终状态回溯到一开始的状态,我们可以设置一个 \(x\)\(y\) 初始分别为 \(n\)\(m\),当 \(s1[x] = s2[y]\) 时,证明这里从 \((x - 1, y - 1)\) 转移过来,否则则是从 \((x - 1, y)\)\((x, y - 1)\) 中较大的那个转移过来。我们只需要在第一种情况时把当前字符加入 \(ans\),最后再反转输出即可。
需要注意的是第一种情况的判断只能是判断字符,而不能通过 \(dp[x][y] = dp[x - 1][y - 1] + 1\) 判断,因为有可能恰好相等,但实际上不可以转移。

ATcoder Educational DP Contest G

题目给了一个有 \(n \leq 1e5\) 个节点 \(m \leq 1e5\) 条边的有向图,问最长的一条路径有多长。
以一个点为起点跑一次 dfs 就可以求出以他为起点的最长路径,但这样复杂度会达到 \(O(n^2)\),所以要记忆化。每个点跑过一次之后记录下来以这个点为起点的最长路径,再用到就直接返回即可。

ATcoder Educational DP Contest H

题目给了一个 \(n \times m, 1 \leq n,m \leq 1000\) 的矩阵,其中有一些格子不能走,只能往右或者往下走,问走到右下角的路线有多少种。
走到每个节点的走法就是他上面节点的走法加左面节点的走法。如果这个节点不能走,那么走到这个格子的方法数为 \(0\)

10.21

ATcoder Educational DP Contest I

题目给了 \(n \leq 2999\) 个奇数个硬币,每个硬币抛出正面的概率为 \(p_i\),反面为 \(1-p_i\),问最后正面的硬币比反面多的概率。
把状态设计为投了前 \(i\) 个硬币中有 \(j\) 个是正面的概率,那么初始情况就是投了 \(0\) 个出现 \(0\) 个正面的概率为 \(1\)。转移就是 \(dp[i][j] = dp[i - 1][j - 1] * p[i] + dp[i - 1][j] * (1 - p[i])\)
最后统计出 \(j \geq \lceil\frac{n}{2}\rceil\) 的所有 \(dp[i][j]\) 的和就是最终答案。

10.22

ATcoder Educational DP Contest J

给了 \(n \leq 300\) 个盘子,每个盘子中装有 \(1,2\)\(3\) 个寿司。每次随机选择一个盘子,如果这个盘子里有寿司就吃一个,否则就什么也不做。问吃光所有寿司的期望轮次。
容易发现状态可以设计为 \(dp[i][j][k]\),表示剩 \(1,2,3\) 个寿司的盘子有 \(i,j,k\) 个时,从初始状态吃到这个状态的期望。我一开始想的比较单纯,分别计算了当前吃 \(1,2,3\) 个盘子的期望次数,但会出现一个问题,就是如果吃某个含有相应数量的寿司之前,吃了另一个有不同数量寿司的盘子,那么转移就不是我们希望的只吃一个要求盘子的情况。
此时叶神下课过来,他给了一种想法,去计算吃掉一个寿司的期望,然后吃掉每一种盘子的期望都加上这个。这种做法因为吃掉每种盘子的概率不同,所以挂掉了。
然后我试着改变状态的设计为从当前状态吃到全零状态的期望,这样就可以得到下面的式子:

\[dp_{i,j,k} = (dp_{i,j,k} + 1) \times p_0 + (dp_{i-1,j,k} + 1) \times p_1 + (dp_{i+1,j-1,k} + 1) \times p_2 + (dp_{i,j+1,k-1} + 1) \times p_3 \]

推导一下可以得到:

\[dp_{i,j,k} = \frac{dp_{i-1,j,k} \times p_1 + dp_{i+1,j-1,k} \times p_2 + dp_{i-1,j+1,k-1} \times p_3}{1-p_0} \]

这样就可以正确的计算每个传进来的期望按概率分配了。用到的是总期望等于每个部分期望乘这个期望的概率。需要注意的是从最终状态往前去推导一般更容易得到递推式。

posted @ 2025-10-16 23:14  vivid_stareium  阅读(4)  评论(0)    收藏  举报