退役前的字符串学习

exkmp:

线性求出字符串的任何一个后缀与自身的lcp长度

设其为(z)数组,(z[i])表示([1,n])([i,n])lcp的长度

考虑从前往后依次求出(z[i])

考虑维护(i+z[i]-1)最大的(j)

那么如果(i<=j+z[j]-1),考虑([i,j+z[j]-1]=[i-j+1,z[j]-1])

(z[i])就从(min(z[i-j+1],j+z[j]-i))继承过来即可

然后剩下的部分暴力往后匹配

注意你如果需要暴力往后匹配,(j+z[j]-1)必然会被当前的(i+z[i]-1)更新,每匹配一位就至少变大(1)

因为如果(min(z[i-j+1],j+z[j]-i)=z[i-j+1])(z[i])是不会更新的,因为两者一样的部分长于(z[i-j+1])(z[i])不会比(z[i-j+1])

综上所述,复杂度是(O(n))

一份含exkmp的代码code



lyndon words and runs

没有lemma的证明(有些没看懂)

lyndon串:一个满足除了本身以外的后缀,字典序都比它本身大的串

一个性质:两个lyndon串(s,t),若(s)严格小于(t),则(st)是lyndon串

一个串的lyndon分解:把一个串分解成(s_1,s_2...s_k),满足(s_1,s_2...s_k)都是lyndon串,且(s_1 geq s_2 geq ... geq s_k),这里(geq)表示字典序不小于

一个性质:一个串的lyndon分解存在且唯一

求lyndon分解:Duval's Algorithm

增量法构造lyndon分解

考虑我们当前已经有([i,|S|])的lyndon分解,要求出([i-1,|S|])的lyndon分解

考虑维护一个栈,栈中每个元素是一个lyndon串的结尾

栈中元素需要满足这些lyndon串不降

向栈中加入(i-1)

若当前(s[i:st[top]] > s[st[top]+1:st[top-1]])

则这两个可以合并,弹出栈顶

runs:定义三元组((i,j,p))是一个run,当且仅当(s_{j+1} eq s_{j-p+1},s_{i-1} eq s_{i+p-1})(p)([i,j])最小的出现至少两次的循环节。

求runs

求出以每个位置为左端点的最长lyndon子串

这个其实就是上面的算法里每一步添加以后的栈顶元素

runs的求解:

对于上面的每一个串([l,r]),以它的长度为周期,向左/右扩展到(l',r'),若([l',r'])的长度不小于([l,r])长度的两倍,则([l',r'])是一个runs

求解的时候要把字符大小关系反过来再求一次lyndon word和runs,才能求出全部的

模板题code

原文地址:https://www.cnblogs.com/deaf/p/14855671.html