DP 套 DP 专训记录

P4590 [TJOI2018] 游园会

先考虑内层 DP。也就是对于串 \(S\) 如何求其与给定串的最长公共子序列。我们有经典暴力 DP:

\[f(i,j)=\max \begin{cases} f(i,j-1)\\ f(i-1,j)\\ f(i-1,j-1)+[s_i=s_j] \end{cases} \]

我们发现,当 \(i\)\(f(i)\) 一定时,后续转移是一定的。于是我们考虑设计状态 \((i,f(i))\)\(\delta\) 是容易得到的,对每个状态模拟一遍内层 DP 得到新状态即可。

我们需要证明状态数足够小。事实上,我们发现 \(f(i)\) 是单调的,且 \(f(i,j+1)-f(i,j)\le 1\),因此只有 \(2^k\) 种差分数组,一一映射状态。同时这告诉我们可以方便地使用差分数组状压后的数表示一个状态。

外层 DP 转移是简单的,考虑 \(f(i,s,k)\) 表示处理到第 \(i\) 个字符位于 DFA 上状态 \(s\)NOI 串匹上了 \(k\) 个字符的前缀字符串方案数即可。

AGC022E Median Replace

考虑如何判定一个固定串是否是好的。题目操作可以表示为“三个连续的零消去两个”和“一对相邻的零一可以删去”。我们考虑如下贪心:从前往后扫描原序列,动态维护一个栈,每次向栈顶弹入当前字符,然后:

  • 若有三个连续的零,直接消去两个,显然不劣。
  • 若出现了 01,直接消去,因为前面那个零总要消掉的,而后面那个一不消掉他也没法和别的零凑对,故而直接和后一个一拼掉不劣。
  • 否则无需额外处理。

只要最后一的数量比零的数量多一定可行。

我们发现栈里任意时刻形如前面一堆一和后面一堆零,再发现最后零的个数必然不超过 \(2\),故而任意时刻只要前面那一坨一的数量超过 \(2\) 就必然胜利。因此我们发现有效的状态只有 \(3\times 3=9\) 种。

外层 DP 是平凡的。可以简单做到 \(O(|S||\Sigma|)\)

CF1142D Foreigner

我们考虑快速计算一个状态的排名。具体地,对于一个已知排名 \(k_x\) 的状态 \(x\),存在合法转移 \(\delta(x,c)=y\),我们考虑计算 \(y\) 的排名 \(k_y\)。只要算 \(y\) 前面有几个点即可。我们发现 \(x\) 之前的点的子节点,以及 \(x\)\(c\) 之前的 \(\delta\) 全在 \(y\) 之前,于是所求即为:

\[k_y=9+(\sum_{i=1}^{k_x-1}i\bmod 11)+c+1 \]

我们发现我们只需要关心各个排名在模 \(11\) 意义下的值即可。上式于是可以改写成:

\[k_y=c+10+\frac{k_x(k_x-1)}{2} \]

同时发现中间状态数仅有 \(11\)。于是内层 DFA 就出来了。

考虑外层转移,平凡地 \(f(i,s)\) 表示考虑到前 \(i\) 个字符位于状态 \(s\) 的方案数,每次把当前位置作为起点的方案加入统计然后枚举所有状态转移即可。

P8352 [SDOI/SXOI2022] 小 N 的独立集

平凡地考虑判定一棵已知树的最大权独立集,\(f(i,0/1)\) 表示 \(i\) 子树是否选 \(i\) 的最大权独立集即可直接转移。故而可以简单设计外层 DP \(h(x,f_0,f_1)\) 计数,转移直接模拟就行,可惜过不了。

换一个算法,我们考虑 \(f(i)\) 表示钦定不选 \(i\)\(g(i)\) 表示不钦定不选 \(i\) 的子树最大权独立集,有 \(g(i)\ge f(i)\)。有转移:

\[f(x)=\sum_yg(y)\\ g(x)=\max(f(x),a_x+\sum_yf(y)) \]

我们发现当某一时刻 \(a_x+\sum_yf(y)\le f(x)\) 时可以直接 \(g(x)\gets f(x)\),不会影响后续转移正确性。同时我们发现由于 \(f(y)\le g(y)\),因此 \(0\le g(x)-f(x)\le a_x\le k\)

故而我们设计 \(h(x,f,d)\) 表示 \(f(x)=f\)\(g(x)=f(x)+d\) 时的方案数,逐个枚举子节点转移:

\[h(x,f,d)h(y,f',d')\to h'(x,f+f'+d',\max(0,d-d')) \]

于是就做完了。

CF924F Minimal Subset Difference

依旧平凡地考虑判定。不难发现其实就是一个尽可能使和趋近于一半的背包,每个值可以任意选择加减。

尝试以 \((i,s)\) 表示前 \(i\) 个数和的绝对值为 \(s\) 作为状态设计自动机,然后发现设计出来的是一个 NFA。首先我们可以证明有效的 \(s\) 的上界为 \(\lfloor\frac{17}{2}\rfloor\times9=72\),其次我们大力暴搜发现幂集构造转 DFA 后有用的幂集状态不超过 \(13000\) 个。

所以我们直接记忆化暴搜搜出所有状态和转移,可以使用 __int128 压位存储状态,然后外层 DP 的话就是一个平凡的数位 DP,最终状态合法仅当状态内最小的 \(s\) 不超过 \(k\)。于是就做完了。

P8497 [NOI2022] 移除石子

超级人类智慧上界放缩题。

考虑判定合法序列。从 \(k=0\) 开始思考。

不难想到就是区间覆盖限制问题,考虑 \(f(i,j,k)\) 表示到 \(i\)\(j\) 个到了 \(i\) 的和 \(k\) 个强制钦定到 \(i+1\) 的,转移是容易的。人类智慧发现只需要 \(j,k\le2\) 即可。

考虑计数的话,我们注意到 \(\ge6\) 的所有 \(a\) 本质相同,于是简单地 DP 套 DP 即可,外层计数 DP 是平凡的。

考虑 \(k>0\) 的情况。我们可以证明,除了下列两种特殊情况外,其余 \(k\) 只要存在 \(<k\) 的方案就必然存在 \(k\) 的方案:

  • \(k=1\),并且所有 \(a\) 均为 \(0\)
  • \(k=1\)\(n=3\) 且所有 \(a\) 均为 \(1\)

于是考虑 \(g(i,j,k)\) 表示 \(f(i,j,k)=1\) 所需的最小 \(k\),转移枚举过程和 \(f\) 没什么区别,转移方程仍然是平凡的。

不难想到 \(>100\)\(g\) 本质相同。再搜一下发现有效状态数很少,只有不到一万,所以直接大力 DP 套 DP 就做完了。

posted @ 2026-04-11 16:34  LastKismet  阅读(30)  评论(0)    收藏  举报