利用自动机模型处理动态规划的转移路径

这个套路俗称 dp 套 dp。

大致思路就是把 dp 的转移路径用一个自动机模型处理出来。

自动机它本身只是一个定义,这里并不怎么利用它的性质。只是因为这种根据一个字符从一个结点转移到另一个结点,和某些动态规划的转移很相似而已。

众所周知有 KMP、ACM、SAM 套 dp 的套路。而对于一些性质没有这么好的问题,就得自己设计一个并不那么高效的自动机,去规划 dp 的转移路径。

有时可以处理一些非常诡异的计数 dp。

一句话概括:把同一层、转移路径相同的状态,压成自动机上的一个结点。

\(\texttt{TJOI2018 }\text{游园会}\)

字符集 \(\Sigma=\{N,O,I\}\)。给定模板串 \(T\),分别对于每个 \(p=0,1,\cdots,\left|T\right|\),求出满足如下条件的字符串 \(S\) 数量:

  1. 长度为 \(n\)
  2. 不存在 \(NOI\) 为它的子串。
  3. \(\left|LCS(S,T)\right|=p\)(Longest Common Substring)。

设计状态 \(dp_{i,j,u}\) 用来计数。其中这里的 \(u\) 主要是用于自动机上的转移,可以看成自动机上的编号,希望把转移路径相同的 \(S\) 放到这上面。\(i,j\) 的定义是套路的,\(i\) 代表考虑大小为 \(i\) 的串,\(j\) 用来避免出现 \(NOI\) 子串。

如果枚举第 \(i\) 位的字符 \(S_i\),由于 LCS 的转移为

\[lcs_{i,t}=\max(\max(lcs_{i-1,t},lcs_{i-1,t-1}+\left[S_i=T_t\right]),lcs_{i,t-1}) \]

因此自动机结点 \(u\) 上应该维护的信息是:对于所有 \(t=0,1,\cdots,\left|T\right|\)\(lcs_{t}\)(因为这个 \(i\) 是自动机结点的深度,所以把 \(i\) 省略掉了) 是多少。注意到给了 \(S_i\) 后,就可以从深度为 \(i-1\) 的自动机结点 \(u\) 确定唯一的深度为 \(i\) 的自动机结点 \(v\),计数就是一个直接的累加。

这样,就完成了一个路径规划。

现在来考虑结点数量。注意到一个自动机结点 \(v\)\(lcs\) 数组的转移

\[{\color{red} {lcs_{v,t}}}=\max(\max(lcs_{u,t},lcs_{u,t-1}+\left[S_i=T_t\right]),{\color{red}{lcs_{v,t-1}}}) \]

因此 \(lcs\) 数组单调不减。继续观察,可以证明,\(0\le lcs_{t}-lcs_{t-1}\le 1\)。因此根据差分数组,这样的数组最多有 \(2^{\left|T\right|}\) 个。因此,自动机每层都只有 \(O(2^{\left|T\right|})\) 个有用的结点。

最后的统计是容易的。总复杂度可以做到 \(O(2^{\left|T\right|}(n+\left|T\right|))\)

\(\square\)

\(\texttt{ZJOI2019 }\text{麻将}\)

\(n\ge 5\) 种不同的麻将,编号依次为 \(1,2,\cdots,n\),每种有 \(4\) 张。

一个形如 \((i,i+1,i+2)\)\((i,i,i)\) 的三元组被称为面子。

一个形如 \((i,i)\) 的二元组被称为对子。

一个麻将集合 \(S\) 是胡的,当且仅当它满足以下两个条件中至少一个

  1. 可以划分成 \(4\) 个面子和 \(1\) 个对子(\(14=4\times 3+1\times 2\))。
  2. 可以划分成 \(7\) 个对子(\(14=7\times 2\))。

先给 \(13\) 张麻将。剩下的麻将随机打乱,每次随便摸一张 不放回去,直到手里的麻将集合存在一个子集是胡的。求期望拿几张才能胡。

用每种排列用了多少次恰好胡了除以总排列数量,主要考虑这些次数的和。

比较经典地枚举次数,看看这个第几次取完还有多少种情况没胡(和 \(\texttt{NOIP2020 }\text{微信步数}\) 类似),这个看起来会比较容易 dp。记第 \(i\) 次还没胡的情况数量为 \(f_i\),这样,答案就是

\[1+\frac{1}{(4n-13)!}\sum\limits_{i=1}^{4n-13}(4n-13-i)!f_i \]

后面我懒得想,先咕咕咕了。

posted @ 2022-04-20 16:12  gsj_z  阅读(142)  评论(0)    收藏  举报