模板2
KMP
nxt[i]: $b[1:i]$ 的最长 border $b[1:nxt_i]$,且 $nxt_i<i$。
void init(){
int p=0;
F(i,2,m){
while(p&&b[p+1]!=b[i]) p=nxt[p];//p+1 尝试与 i 匹配
if(b[p+1]==b[i]) p++;
nxt[i]=p;
}
}
void kmp(){
int p=0;
F(i,1,n){
while(p&&(p==m||b[p+1]!=a[i]) p=nxt[p];//p==m
if(b[p+1]==a[i]) p++;
f[i]=p;
}
}
Z 函数
$z_1=0$。
z[i]:$b[i:n]$ 与 b 的 LCP 长度。
void z_init(){
z[1]=0;//
for(int i=2,l=0,r=0;i<=m;i++){
if(i>r) z[i]=0;
else z[i]=min(z[i-l+1],r-i+1);
while(i+z[i]<=m&&b[1+z[i]]==b[i+z[i]]) z[i]++;
if(i+z[i]-1>r) l=i,r=i+z[i]-1;
}
}
void z_alg(){
for(int i=1,l=0,r=0;i<=n;i++){
if(i>r) p[i]=0;
else p[i]=min(z[i-l+1],r-i+1);
while(i+p[i]<=n&&b[1+p[i]]==a[i+p[i]]) p[i]++;
if(i+p[i]-1>r) l=i,r=i+p[i]-1;
}
}
Manacher
p[i]:以 $i$ 为中心的最长回文半径。$[i-p_i+1,i+p_i+1]$ 为回文串。
void init(){
int m=0;
s[++m]='#';//s[0]='(',s[1]='#'
F(i,1,n) s[++m]=a[i],s[++m]='#';
s[0]='(';s[m+1]=')';
}
void manacher(){
p[1]=1;
for(int i=2,k=1;i<=m;i++){//k=1,当前最优端点属于 1 的回文串
if(i>k+p[k]-1) p[i]=1;
else p[i]=min(k+p[k]-i,p[2*k-i]);
while(s[i-p[i]]==s[i+p[i]]) p[i]++;
if(i+p[i]>k+p[k]) k=i;
}
}
AC自动机
fail:指向某状态所表示的字符串的最长后缀。
//AC
struct node{
int trs[26],fail;
}t[N];
int tot=1;//p=1 is used
void ins(){
int p=1;
F(i,1,n){
int c=s[i]-'a';
if(!t[p].trs[c]) t[p].trs[c]=++tot;
p=t[p].trs[c];
}
}
void bd(){
F(i,0,25) t[0].trs[i]=1;
t[1].fail=0;
queue<int>q;
q.push(1);
while(!q.empty()){
int u=q.front();q.pop();
F(i,0,25){
int &v=t[u].trs[i];//&v
if(v) t[v].fail=t[t[u].fail].trs[i],q.push(v);
else v=t[t[u].fail].trs[i];
}
}
}
SA
//SA
int m=256;
int sa[N],rk[N],tmp_rk[N],id[N],ct[N],px[N],ht[N];
bool same(int x,int y,int k){
int p=x+k<=n?tmp_rk[x+k]:-1,
q=y+k<=n?tmp_rk[y+k]:-1;
return tmp_rk[x]==tmp_rk[y]&&p==q;
}
void init(){
F(i,1,n) rk[i]=s[i];
F(i,1,n) ct[rk[i]]++;
F(i,1,m) ct[i]+=ct[i-1];
for(int i=n;i>=1;i--) sa[ct[rk[i]]--]=i;
for(int k=1,p=0;k<n;k<<=1,m=p){
p=0;
F(i,n-k+1,n) id[++p]=i;
F(i,1,n)if(sa[i]>k) id[++p]=sa[i]-k;
F(i,0,m) ct[i]=0;
F(i,1,n) ct[px[i]=rk[id[i]]++;
F(i,1,m) ct[i]+=ct[i-1];
for(