小序:学习后缀自动机是要有耐心的,clj的论文自己看真心酸爽!(还是自己太弱,ls,oyzx好劲啊,狂膜不止)
刚刚在写博客之前又看了篇论文,终于看懂了,好开心
正文:
一.后缀自动机是什么?
答:后缀树+自动机
二.能处理什么问题?
答:字符串之类的啊,还要问
三.有什么优点?
答:代码短,时间复杂度低
四.怎么写?
1.首先你得知道什么是自动机和什么是后缀树?
这个是基础问题,你可以去查查资料,本文不再阐述。
2.后缀树建树点是N2的,怎么破?
clj的ppt写的很详细,但是不是很容易懂,于是我这个蒟蒻就讲讲吧。
(1).我们要破点又要能表示所有的状态势必就要合并点。
可是什么样的点是可以合并?
这可谓是后缀自动机学习需要了解的关键之一,下面我就讲一下我的想法:
我们首先要定义一个right数组,表示一个子串s在母串ss中的右端点位置集合,例如aab在aabaabab中的right[s]={3,6};
这个有什么用呢?
我们来想一个这样的问题如果两个串s1,s2的right集合有交集那会是什么情况?
先给出结论等下在证明:设sum[right[s]]代表right[s]集合的元素个数,如果两个串s1,s2的right集合有交集,并且sum[s1]>=sum[s2]则s1是s2的子串;
证明:设right[s1]∩right[s2]={v1,v2,v3.....,vk},就那v1来看吧,那么s1和s2势必是v1前面的某两个点到v1所形成的字符串,那么为什么sum[s1]>=sum[s2]则是s1是s2的子串?一个显然的结论:如果一个子串的sum更大,那么它的长度越短。
证明了这些东西,那么right集合相等的就可以合并了啊,是不是很神,然后我们就可以利用right集合建一颗树了(可以表示出一个串的从属情况)
如下图:
这样就可以了吗,能表示所有的子串状态吗?显然是不行的,不然要自动机干嘛(可以自己yy一下)。
(2).状态数的线性证明.
clj的ppt非常详细,自己看看吧,我怕我自己的证明不严谨将读者带入歧路。
(3).构造过程:
设:已匹配串s,待匹配字符x,已建节点p。
1.新建节点np,然后从p开始向fa[p]跳,如果有连出为x的边并且val[p]+1=val[son[p][x]]则向np连一条为x的边。否则执行步骤2.
2.
3.到这里你可能就要大喊一句为什么?为什么要新建节点?
论文上写很好,你们如果不理解可以留言问我咯【本蒟蒻QQ:1481632287】
五.总结:这个东西学起来有点难懂,但是学完了会发现还是很简单的,虽说可能它的用处比后缀数组要小但是它的代码短,又高效这才是更适合oi比赛的东东。
刚刚发现一个好强的博客:http://blog.csdn.net/wangzhen_yu/article/details/45481269;