后缀自动机刷题总结

写在前面:

迪哥说这个专题前面的题都比较板子,然而菜鸡博主感觉一个比一个难,一定是我太菜迪神太巨了

希望这篇博客能使自己理解更加深刻一些吧

 


 

弦论

先考虑$Dp$出$endpos$集合大小:

设$f[i]$代表$SAM$里$i$节点的$endpos$大小

$f[i]=(i$是前缀节点$)+\sum\limits_{(i,j)\in{parenttree}}f[j]$

之后转移$g[i]$代表从$i$出发的子串个数(空串也算)

$g[i]=T==0?1:f[i]+\sum\limits_{(i,j)\in{parenttree}}g[j]$

其中$i$不能是根节点

 


 

生成魔咒

其实就是上一道题的动态化:

因为后缀自动机里每个串只会被唯一节点唯一接受

所以$ans=\sum\limits_{i=1}^{cnt}len[i]-len[fa[i]]$

 


 

公共串

考虑先对于一个串建出$SAM$

之后对于其他串扔到$SAM$里匹配

如果可以走就继续走

否则跳父亲来减少前面的长度去尽量匹配

对于每个点求出所有其他串在这个点的匹配长度最小值便是最终答案

 


 

差异

$SAM$处理$prefix$比较难,考虑把串翻转变成了$suffix$

有一个很好的性质:两个串的最长$suffix(lcs)$便是$parent$树上$lca$的$len$

于是问题转化为了以每个点为$lca$的$endpos$点对,$dfs$一遍便可以求出


 

品酒大会

与上一道题基本相同

只是需要维护一个最小最大值

最后做一边前缀和即可


 

工艺

也就是求最小循环位移

考虑断环成链,建出SAM,之后有一个问题:

我们是否会在[n+1,n*2]范围内跑到n*2结果没路了

答案是否定的,因为[n+1,n*2]和[1,n]是完全相同的

所以直接贪心跑最小的出边即可


 

SubString

这道题说实话很裸啊

$LCT$维护子树信息或者维护懒标记便可以处理动态问题了


 

诸神眷顾的幻想乡

广义后缀自动机我真的理解不深刻

由于叶子节点不超过$20$个

所以可以把每个叶子作为根$dfs$

建出一个广义$SAM$

统计一下本质不同子串个数即是答案


 

Cheat

分成若干段显然是个$Dp$

先二分$L_0$

设dp[i]代表以i为结束点的最大合法长度

那么$dp[i]=max(dp[j]+i-j)(i-j\in{[L_0,w[i]]})$

循环到$i$便把$i-L$加入到队列里,便消除了$L$的影响

发现$i-w[i]$是单调不降的

所以可以用单调队列优化$Dp$

总复杂度$O(len*log_2(n))$


 

你的名字

是道神仙题

先考虑$68pts$:

对于$S$建出$SAM$,再把$T$扔上去匹配

直接计算一定会算重

那就对$T$也建出一个$SAM$

之后只在每个$SAM_T$节点统计答案

设$f[i]$代表$T_i$在$S$上的最长匹配长度

$g[i]$代表$SAM_T$里的$i$节点的最小的$endpos$

那么$ans=\sum\limits_{i=2}^{cnt_T}max(0,len[i]-max(len[fa[i]],f[g[i]])$

$100pts:$

有了$L,R$的限制,便不能确定当前匹配的串是否在$[L,R]$的范围内

所以需要用主席树上树启发式合并得出每个$perenttree$上的点的$endps$集合

便可以$log$查询$[L+z,R]$是否有$endpos$了($z$为当前匹配长度)

注意如果没有则把$z--$而不是直接跳父亲

(直接跳父亲会$WA96$分,这$CCF$的数据也太水了吧)

无论如何匹配复杂度都是$O(n)$的,因为匹配过程类似两个指针从$1$扫到$n$

匹配次数显然是线性的

你可能感兴趣的:(后缀自动机刷题总结)