引入

本文将介绍 DP 套 DP 的思想,并通过两道例题展示它如何应用到具体问题中。

思想

所谓「DP 套 DP」,实际上指的是在动态规划的过程中,把一个子问题的求解过程(通常是一个 DP)抽象成一个自动机(DFA),然后在这个自动机的基础上再设计一层新的 DP 的方法。

这种技巧主要应用于一类 序列计数概率期望 问题。一个典型的问题具有如下结构:

  • 给定字符集 和它上面一个长度为 的「合法序列」的集合 。根据字符集不同,序列可以是二进制串、数字串、状态序列等。
  • 对于每一个具体的序列 ,可以通过动态规划来判断它是否合法(即 ),计算它的权值或求出相关值。
  • 最终,我们希望统计集合 中所有序列的数目、总权值、期望值等。

这时,枚举所有序列是不可行的。于是我们考虑将「判断一个序列是否合法」的过程(即内层 DP)抽象为一个 确定有限状态自动机(DFA)。一般地,对于固定的序列 ,内层 DP 的状态函数可以表示为 ,即已经处理完序列 的长度为 的前缀,且其他状态分量为 时某个量的取值。相应地,内层 DP 的状态转移方程为

也就是说,函数 由之前的函数 和当前的字符 唯一确定。如果将函数 看作是自动机的一个状态,那么,内层 DP 的状态转移方程就给出了自动机的一个转移。因此,内层 DP 对应的自动机 结构如下:

  • 状态集合 就是所有可能的 对应的函数 的集合;
  • 转移函数 就是内层 DP 的状态转移方程中的
  • 起始状态 通常是显然的,即内层 DP 的初始状态;
  • 接受状态集合 就对应着所有的合法序列

函数 本身可能相当复杂,因此,在处理具体问题时,通常需要进行 状态压缩 或结合 DFA 最小化的技巧来压缩状态空间。这也是 DP 套 DP 相较于暴力 DP 能够显著降低时空复杂度的主要原因。

将内层 DP 抽象为 DFA 后,就可以在这个 DFA 上设计一个新的 DP 用于求解原问题,即外层 DP。为方便表述,以简单的计数问题为例。外层 DP 的状态函数定义为 ,即处理到长度为 的前缀时,到达 DFA 中状态 的前缀的数目。它的状态转移方程为

起始状态当然是 ,而最终要求的答案通常可以根据 简单计算得到。外层 DP 实际上是 DAG 上 DP 的特殊情形。

例题

接下来的两个例题会详细说明 DP 套 DP 的一般做法。

例一

给定一个字符集为 ACGT 的字符串 ,且 。对于每个 ,求有多少个长度为 ,字符集 ACGT 的字符串 ,满足它与 的最长公共子序列长度为

例二

假设麻将牌有 种大小的牌,每种大小有 张牌。定义面子为三张相邻大小的麻将牌 (顺子)或三种相同大小的麻将牌 (刻子),对子为两张相同大小的麻将牌 。定义一个麻将牌的序列是胡的,当且仅当它(看作多重集合)可以拆成四个面子和一个对子,或者七个不同的对子。给定 张麻将牌,问期望再摸多少张牌可以满足存在一个胡牌的子序列的条件。

习题

此文件夹下有0条笔记。