关于 AC 自动机复杂度
查看原帖
关于 AC 自动机复杂度
204989
_Iva楼主2022/10/11 16:56

先设 S|S| 为一个模式串长度, S|\sum_S| 为模式串总长,|\sum| 为字符集大小,T|T| 为一个文本串长度, nntrietrie 树点的个数

AC 自动机有两种 getfailgetfail 的方式:

方法一:每个点都访问的所有字符集元素,若无此儿子则赋值为 chfailx,ich_{fail_x,i} ,若有儿子直接 failchx,i=chfailx,ifail_{ch_{x,i}} = ch_{fail_x,i} 。这样路径压缩,匹配时跳 failfail 的次数会减少,但 getfailgetfail 的复杂度至少 S|\sum||\sum_S|

方法二:暴力跳 failfail 直到第一个存在 chy,ich_{y,i}yy 。我们来分析这个复杂度。

1.对于 getfailgetfail ,看起来跳的很多,但我们考虑每个模式串(一条链),儿子的 failfail 一定是接着它父亲跳的,而跳一次深度就要 -1,所以一条链跳 failfail 复杂度 Θ(S)\le \Theta(|S|) ,全部点跳 failfail 的复杂度 Θ(S)\le\Theta(|\sum_S|) ,没问题。

2.对于 bfsbfs , 仍然访问0~25每个节点会炸,所以用个 vectorvector 存一下就做到 Θ(n)<Θ(S)\Theta(n) < \Theta(|\sum_S|) ,也没问题。

3.对于匹配的状态转移,虽然每次在失配时不能直接转移,而是要一直跳 failfail ,但同上,跳 failfail 至少使深度-1,所以复杂度 Θ(T)\Theta(|T|) 仍然没问题。

4.对于匹配时计算贡献时跳的 failfail,只需打 ed=1ed = -1 的标记就还是 Θ(T)\Theta(|T|) ,没问题。

综上,方法一优化了匹配转移的常数,但增加了 getfailgetfail 的复杂度,而此题是单文本串,按理来说方法二会爆杀方法一……

但我测的结果是方法二竟然慢1.5倍???

方法一评测记录 206ms

方法二评测记录 298ms

为什么捏qwq

vector 不至于慢 39 倍吧

2022/10/11 16:56
加载中...