Loading

AC自动机练习笔记

AC自动机

这里 \(ch[x][i]\) 是在 \(AC\) 自动机上, 现在在 \(x\) 节点, 增加一个字符 \(i\), 会跳到哪个节点。
\(Fail[x]\) 表示如果在位置 \(x\) 失配(就是在原来的\(Trie\)树上找不到节点), 节点 \(x\) 最长公共后缀的节点编号

建立 \(AC\)自动机

分为 \(2\) (\(3\)) 个步骤:

1. 建 \(Trie\)

普通建立即可

2. \(BFS\) 得出 \(Fail\) 数组

考虑对于一个节点 \(x\), 要对于他下面的某个节点 \(v\) 进行操作(v是 \(x\) 状态下第 \(i\) 个叶子节点)

  1. 对于没有下面的这个节点(\(v = 0\)) 将 \(ch[x][i] = ch[fail[x][i]\)
  2. 如果有该节点, 那么 \(fail[v] = ch[fail[x]][i]\)

(3. 建立 \(Fail\) 树)

有时可以不用。
对于每一个 \(x\), 建立一条从 \(fail[x]\)\(x\) 的边
这样方便知道最长的后缀, 在做题时, 这颗树常常发挥很大用场

练习

CF1202E You Are Given Some Strings...
考虑把两个串拼接起来, 在字符串中匹配时, 两个串拼接处的位置 \(k\)
枚举 \(k\), 然后求出以每个可以在文本串中匹配的字符串以位置 \(k\) 结束以及开始的字符串个数, 相乘即可。
求以位置 \(k\) 开始的字符串个数时, 把每一个字符串反转再匹配即可。

P5357 【模板】AC自动机(二次加强版)
模板, 对于 \(AC\)自动机 上的每一个节点统计出现次数, 建立 \(Fail\) 树, 一遍 \(dfs\)\(Fail\) 树上的节点出现次数加上其子树出现次数总和即可。

CF163E e-Government
需要建立 \(fail\)
对于'+' 操作, 在 \(fail\) 树上该字符串串尾所对应状态的 \(Fail\)树 上的子树的答案加一, 就是让所有包含他的状态答案 \(+1\)
对于'-' 操作, 在 \(fail\) 树上该字符串串尾所对应状态的 \(Fail\)树 上的子树的答案减一, 就是让所有包含他的状态答案 \(-1\)
对于'?'操作, 遍历到每一个状态时, 只要把答案加上这个状态所对应的答案即可。
发现这个可以在 \(dfs\) 序上线段树维护,于是就解决了这道题目。

CF547E Mike and Friends
同样, 也要建立 \(Fail\) 树。
寻问 \(s_k\)\(s_l .. s_r\) 中出现几次, 拆分成 \(s_k\)\(s_1 ... s_r\) 中出现的次数 减 \(s_k\)\(s_1 ... s_r\) 中出现的次数,离线查询。
在建立完 \(Fail\) 树之后, 一个一个插入字符串。插入字符串 \(s_m\) 时将字符串 \(s_m\) 的每一个前缀对应状态的答案增加一即可。插入完解决对于任意 \(k\), \(s_k\)\(s_1 ... s_m\) 中出现的次数, 由于在 \(s_k\) 的子树中的状态所对于的字符串都包含 \(s_k\), 所以只要查询 \(Fail\) 树上的子树答案和,\(dfs\) 序 + 树状数组即可。

CF1437G Death DBMS
题解

CF587F Duff is Mad
根号分治,对于长度 \(\le B\) 的扫描线处理询问,对于长度 \(> B\) 的对于这个串单独处理询问。

CF86C Genetic engineering
AC 自动机上套个 dp, 让 \(dp_{i, j, k}\) 表示现在在算第 \(i\) 个字符,在 AC 自动机上的第 \(j\) 个节点,没有匹配的长度为 \(k\)

CF696D Legen...
AC 自动机套个矩阵乘法,\(dp_{i, j}\) 表示现在在算第 \(i\) 个字符,在 AC 自动机的节点 \(j\)

posted @ 2020-08-09 19:14  zhoukangyang  阅读(120)  评论(0编辑  收藏  举报