AC自动机

例题(从易到难):
模板
poi 病毒

模板题,没什么营养价值
建立Trie图后tarjan判环即可。

CF710F

模板题,没什么营养价值
二进制分组+AC自动机即可。

lg3121

以前在jzoj上做过单串版本。
用AC自动机+栈,每次插入一个字符,维护在AC自动机上的匹配点。
栈中维护从栈底匹配到栈的某个点在AC自动机上的节点。
当栈顶能够被匹配,则弹出匹配的字符串。

[JSOI2007]文本生成器

简单题。
用容斥,转化成不可读的单词的个数。
显然用dp,设\(f_{i,j}\)表示长度为\(i\),走到第\(j\)个节点。
把可读单词标记成不能访问,\(j\)不能访问标记点。

[BJOI2017]魔法咒语

把禁止串在AC自动机上标记,不能访问。
\(f_{i,j}\)表示第\(i\)个节点,转移到\(j\)的方案。
转移显然。
后面基本词汇最多为\(2\)的情况只会转移到\(f_{i+2,k}\),用矩阵乘法拆点维护\(f_{i},f_{i+1}\)即可转移。

[HNOI2006]最短母串问题

字典序最小很难做。
发现一个字符串上一个字符如果没被任何合法串覆盖,则删除更优。
\(f_{i,j}\)表示状态为\(i\),最后一个字符串为\(j\)的最小长度。
枚举\(i,j\)串能够拼接起来的长度转移。
在比较字典序时用string即可。

lg3311
CF585F
CF163E

简单题
考虑把原串拿到AC自动机上去匹配,在匹配的过程中计算答案。
当匹配到\(i\)时,\(i\)结尾的方案数就是fail树上它到根节点的被激活节点数
用dfs序+bit维护即可。
CF1437G

做法0:考虑LCT/树剖,显然一个字符串匹配到第\(i\)个位置,答案就是fail树上到根的权值最大值。
用树剖/LCT维护
做法1:考虑线段树,根据前面的分析,我们要支持修改和查询一个点到根的最大值。
考虑离线求。
dfs整个fail树,维护以时间为下标的线段树。
把所有修改操作挂在fail树上,然后在dfs到某个点时,运行其对应修改操作。
把所有在这个节点的修改操作按照时间排序,如果某个操作的生效时间为\([l,r]\),则把线段树上\([l,r]\)对修改值取最大值。
查询时直接查询当前操作时间对应结果即可。
用可回退化线段树(用栈记录操作),时间复杂度$O(n\log_2n)

阿狸的打字机
jzoj4348

把询问串在AC自动机上匹配,我们需要知道fail树到根节点上和\(s,t\)路径匹配的节点数量。
树链剖分后把链按照dfs序重标号,则事实上拆成了连续的\(\log_2n\)条链。
知道fail树上到根的连续标号节点的值可以可持久化线段树。

CF1400F

CF547E

先差分,变成询问\(s_k\)\(s_{1...x}\)中出现多少次。
考虑按照\(x\)扫描线
从小到大插入\(s_i\),考虑它对某个字符串的贡献。
它事实上是\(s_i\)每个前缀的节点所代表的字符串到根路径的节点值+1,用dfs序+bit维护。
查询也可以dfs序+bit,查询对应节点子树节点个数即可。
cf590E
lg5840

套路题
发现\(T\)改变,考虑对\(s_i\)建立AC自动机。
每插入一个字符串时,把这个字符串在AC自动机上匹配。
在匹配时,所有匹配节点到根节点的链上的所有点都要+1。
事实上这是经典的问题。
可以按照dfs序排序,相邻两个点的lca处权值-1,每个点的权值+1,则一个点末尾的字符串个数就是它到根的权值和。
用dfs序+bit维护。

回忆树

考虑树分治,每次在当前路径\(x->y\)包含重心时计算答案。
设当前重心为\(c\)
考虑\(c->x\),\(c->y\)对答案的影响,可以把这条路径的字母在AC自动机上匹配,用bit把访问过的节点打上标记。
在dfs出当前节点后撤回。
然后查询\(s\)子树上是否有标记点。
然而事实上我们发现\(s\)跨过重心的没有求。
这部分可以暴力\(kmp\),这是因为跨过重心的对答案有影响的串长度只有\(O(|2S|)\)

CF587F
bzoj3768
CF1110H
lg7582

做法1:分块
sub2可以ac自动机套线段树。
全部数据可以ac自动机套分块。
每个块维护add,fz标记,表示当前块先被赋值成fz,然后加上add。
在区间赋值时add=0,fz=值
在区间加法是add+=val
给每个节点额外维护一个val,表示val+fz+add是原值。
在区间加法/赋值时散块节点可以先查询原值,然后就能知道新值。
在查询时,非整块用AC自动机+dfs序。
这需要快速知道一个节点的值,用val+fz+add即可。
整块用AC自动机,把当前串在AC自动机上匹配。
这事实上需要知道一个点到根节点的路径值。
先求出每个节点只有val的答案,用dfs序+bit。
这样子散块赋值就只需要更新\(\sqrt{n}\)个bit了。
然后由于整个块的val,fz都是一样的,只需要知道当前节点fail树到根的节点个数即可。

[xr4]文本编辑器

loj6681

CF917E

[GDOI2019]小说

先考虑60分做法。

[GDOI2019]小说 加强版

由于要求精确解,不能分数规划了。

posted @ 2020-09-28 10:23  celerity1  阅读(164)  评论(0编辑  收藏  举报