字符串
字符串
KMP
\(p_i\)表示\(s_{1...i}\)的最长真前缀,真后缀(“真”即是不包括原串)相等
处理就很简单,每个i就判断能否更新i-1的答案,如不行就i变成\(p_{i-1}\)再处理
Fu(i,2,m+n+1){
int j=p[i-1];
while(j>0&&a[i]!=a[j+1]) j=p[j];
if(a[i]==a[j+1]) p[i]=j+1;
}
EXKMP
\(p_i\)表示\(s_{0...n}\)和\(s_{i...n}\)的LCP长度
对于i,考虑一个\(s_{l,r}\)为s的最大的前缀(l<i)
i<=r时,则\(s_{i..r}=s_{i-l,r-l}\),即\(p_i\geq min(p_{i-l},r-i+1)\)
然后就可以暴力扩展,更新l,r
时间复杂度可以保证,因为每次暴力扩展,r都会更新
Fu(i,1,n+m){
if(i<=r) p[i]=min(p[i-l],r-i+1);
while(b[p[i]]==b[i+p[i]]) p[i]++;
if(i+p[i]-1>r) l=i,r=i+p[i]-1;
}
Manacher
大概思路就是现在已经确定了一个最右边的回文串,中心为mm,最右边为mr
我们枚举的以i为中心的回文串,若在最右边的回文串内,那么发现它一定有个对称的左边,然后处理一下
否则就重头开始匹配
时间复杂度:发现每次匹配mr都会变大,所以是\(O(n)\)的
Fu(i,2,n*2){
int k=i>mr?1:min(d[mm*2-i],mr-i+1);
while(s[i+k]==s[i-k]&&i+k<=n*2+1) k++;
d[i]=k;
if(mr<i+k-1) mr=i+k-1,mm=i;
ans=max(ans,k-1);
}
AC自动机
先把trie树建出来,然后类似建kmp
void getfail(){
q[1]=0;
while(l<r){
l++;
Fu(i,0,25){
int u=trie[q[l]].son[i];
if(u){
q[++r]=u;
trie[u].fail=l==1?0:trie[trie[q[l]].fail].son[i];
}
else trie[q[l]].son[i]=trie[trie[q[l]].fail].son[i];
}
}
}
void find(){
int o=0;
Fu(i,1,n){
o=trie[o].son[s[i]-'a'];
int u=o;
while(u&&trie[u].bj!=-1){
ans+=trie[u].bj;
trie[u].bj=-1;
u=trie[u].fail;
}
}
}