退役前的字符串学习
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}\neq s_{j-p+1},s_{i-1}\neq 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