dp套dp 学习笔记

定义

在 dp 时,我们经常会设计一个状态,接着给一些状态的初始值,然后让 dp 从某个状态向某个状态转移。最终计算答案。

然后我们吧 dp 状态看成结点,转移看成边,我们发现他就是 DFA 呀。

所以我们可以直接记录在若干步之后在 DFA 上的 \(u\) 号节点的方案数。

所以,在 dp套dp 里面,我们就将内层 dp 的结果作为外层 dp 的状态进行 dp。

例题

举个例子,加深理解。

[TJOI2018] 游园会

  • 求长度为 \(n\),字符集为 \(\left\{ \mathrm{N},\mathrm O,\mathrm I\right\}\),与给定字符串 \(S\)\(\mathrm {LCS}\)\(len\) 的字符串数量。
  • \(|S| \leq 15\)\(n \leq 10^3\)

我们显然有 \(f_{i,j}=\max(f_{i-1,j},f_{i,j-1},f_{i-1,j-1}+(S_i==T_j))\) 的求 \(\mathrm {LCS}\) 的 dp。

第一部分最后一句中,我们提到外层 dp 的状态就是内层 dp 的结果,于是一个最暴力的想法就是记录所有 LCS 作为状态。

此时,我们要记录的是长度为 i,和 \(S\)\(\mathrm {LCS}\) 为某个数组的字符串数量。

然而我们发现,如果我们在某个字符串后面加一个新的字符,只会新生成一行 LCS而这一行 LCS 完全通过上一行生成!

于是我们只要记录 LCS 最后一行为某个数组的字符串数量了。

然后我们还发现 \(LCS_{x+1,y}-LCS_{x,y}\) 只能是 0 或者 1,于是我们还能差分最后一行得到一个 01 字符串并再次状压。

对了,然后还要记录是否以 N, NO 为后缀。

然后就可以得到优美的代码了。

posted @ 2025-03-25 14:43  ylzqwq  阅读(11)  评论(0)    收藏  举报