序列自动机是接受且仅接受一个字符串的子序列的自动机
状态
由子序列的性质,若s包含n个字符,则构造的序列自动机包含
因此我们可以通过序列自动机获得它的每一个子序列
如abcab的序列自动机如下
我们可以维护一个指针
对于例子中的字符串,
这样我们可以通过一个位置x开始不断跳to指针来得到一个s的子序列
为了方便,我们可以设
性质
由图可以看出,前n个状态接受长度为
因此我们可以动态的构造序列自动机,即每在尾部新增一个字符c,就新增一个状态p,让前面所有不能接受c的状态q接受c转移到p
构建
字符集较小
对于字符集较小,如a-z,我们可以直接维护
从后往前倒叙枚举每一个位置i,构建
首先让字符集中搜友字符c都执行
时间复杂度
1 | void build() |
字符集较大
此时直接维护to指针显然捉襟见肘,我们可以改为使用可持久化线段树维护,即i代表的线段树为它的
1 | void plant0(int &o,int l,int r){ |
应用
判断s是否为t的子序列
将s扔进t的序列自动机,看是否能转移到底
统计s的本质不同子序列个数
记忆化搜索:
,加一是因为空序列也是子序列