回文自动机/回文树

回文自动机

结构

回文树大概长这样

在这里插入图片描述

和其它自动机(但是它却叫「回文树」)类似的,它也是由转移边和 fail 指针组成,每个节点都可以代表所有对应它的回文子串。

因为回文串长度分为奇数和偶数,我们可以像 manacher 那样加入一个不在字符集中的字符(如 ‘#’)作为分隔符来将所有回文串的长度都变为奇数,但是这样过于麻烦了。有没有更好的办法呢?

答案自然是有。更好的办法就是建两棵树,一棵树中的节点对应的回文子串长度均为奇数,另一棵树中的节点对应的回文子串长度均为偶数。

和其它的自动机一样,一个节点的 fail 指针指向的是这个节点所代表的回文串的最长回文后缀所对应的节点,但是转移边并非代表在原节点代表的回文串后加一个字符,而是表示在原节点代表的回文串前后各加一个相同的字符(不难理解,因为要保证存的是回文串)。

我们还需要在每个节点上维护此节点对应回文子串的长度 len,这个信息保证了我们可以轻松地构造出回文自动机。

建造

回文自动机不同于其他自动机的地方在于它有两个初始状态,分别代表长度为 − 1 -1 1 0 0 0 的回文串。我们可以称它们为奇根,偶根。它们不表示任何实际的字符串,仅作为初始状态存在,这与其他自动机的根节点是异曲同工的。

偶根的 fail 指针指向奇根,而我们并不关心奇根的 fail 指针,因为奇根不可能失配(奇根转移出的下一个状态长度为 1 1 1,即单个字符。一定是回文子串)

类似后缀自动机,我们增量构造回文自动机。

考虑构造完前 p − 1 p-1 p1 个字符的回文自动机后,向自动机中添加在原串里位置为 的字符。 我们从以上一个字符结尾的最长回文子串对应的节点开始,不断沿着 fail 指针走,直到找到一个节点满足 $Sp = Sp-len-1 ,即满足此节点所对应回文子串的上一个字符与待添加字符相同。

这里贴出论文中的那张图

在这里插入图片描述
我们通过跳 fail 指针找到 A 所对应的节点,然后两边添加 X 就到了现在的回文串了(即 XAX ),很显然,这个节点就是以 结尾的最长回文子串对应的树上节点。(同时,这个时候长度 节点优势出来了,如果没有 X 能匹配条件就是同一个位置的 ,就自然得到了代表字符 X 的节点。)此时要判断一下:没有这个节点,就需要新建。

然后我们还需要求出新建的节点的 fail 指针。具体方法与上面的过程类似,不断跳转 fail 指针,从 A 出发,即可找到 XAX 的最长回文后缀 XBX ,将对应节点设为 fail 指针所指的对象即可。

显然,这个节点是不需新建的, A 的前 位和后 位相同,都是 B ,前 位的两端根据回文串对应关系,都是 X ,后面被钦定了是 X ,于是这个节点 XBX 肯定已经被包含了。

如果 fail 没匹配到,那么将它连向长度为 的那个节点,显然这是可行的(因为这是所有节点的后缀)。

正确性证明

还是在图上

增加当前字符 X ,如果 XAX 的后缀没有被包含在树中,那才是不正确的,相反如果每次增加时所有后缀都在树上就是正确的

我们找之前 XAX 的 fail 的时候,已经证明了 XBX 已经被包含在树中了

同理找 XBX 的 fail 时会证明一个比 XBX 短的后缀在树中

类似归纳法递归下去,所有回文串就都会在树中,于是这是正确的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值