字符串算法整理(upd:2022.1.21)
字符串
by AmanoKumiko
1.Hash
适用范围:灵活
2.可持久化Trie
https://oi-wiki.org/ds/persistent-trie/
struct Trie{
int ch[M][2],last[N],cnt,val[M];
void insert(int x,int v){
int nx=last[x],ny=last[x-1];
fd(p,29,0){
int g=v&(1<<p)?1:0;
val[nx]=val[ny]+1;
if(!ch[nx][g])ch[nx][g]=++cnt;
ch[nx][!g]=ch[ny][!g];
ny=ch[ny][g];nx=ch[nx][g];
}
val[nx]=val[ny]+1;
}
int query(int x,int y,int v){
int res=0;
x=last[x-1];y=last[y];
fd(p,29,0){
int g=v&(1<<p)?0:1;
if(val[ch[y][g]]-val[ch[x][g]]){res|=1<<p;x=ch[x][g];y=ch[y][g];}
else x=ch[x][!g],y=ch[y][!g];
}
return res;
}
void build(int x){if(!last[x])last[x]=++cnt;}
}t;
Problems
适用范围:一般为异或题
PS:上为常见的可持久化01Trie
3.Manacher
https://oi-wiki.org/string/manacher/
F(i,1,n){
d[i]=i>r?1:min(d[(r-i)+l],r-i);
while(s[i-d[i]]==s[i+d[i]]&&i-d[i]>=1&&i+d[i]<=n)d[i]++;
if(i+d[i]>r)l=i-d[i],r=i+d[i];
}
适用范围:最长回文串,回文串个数
Problems:
PS:回文题一般也可用字符串哈希求解
4.AC自动机
https://www.cnblogs.com/hyfhaha/p/10802604.html
fail:拥有相同后缀的前缀的深度最大的点
struct ACM{
int son[P][26],fail[P],p;
void insert(int x){
int u=1;
F(j,1,len[x])!son[u][s[x][j]-'a']?u=son[u][s[x][j]-'a']=++p:u=son[u][s[x][j]-'a'];
}
void build(){
F(i,0,25)son[0][i]=1;q.push(1);
while(!q.empty()){
int u=q.front();q.pop();
F(i,0,25){
int v=son[u][i],Fail=fail[u];
if(!v){son[u][i]=son[Fail][i];continue;}
fail[v]=son[Fail][i];q.push(v);
}
}
}
}t;
适用范围:匹配
Problems:
PS:
遇到AC自动机+dp时,不应该只是用在AC自动机上dp的思想设状态,要结合别的思想,状压、容斥、正难则反…
遍历AC自动机时,不能粗暴枚举,而应该按照bfs序
5.SA
https://oi-wiki.org/string/sa/#_13
struct SA{
int n,sa[N],rk[N],fir[N],sec[N],t[N],height[N];
void get(){
n=strlen(s+1);
memset(t,0,sizeof(t));
F(i,1,n)t[fir[i]=s[i]]++;
F(i,1,max(122,n))t[i]+=t[i-1];
Fd(i,n,1)sa[t[fir[i]]--]=i;
for(int len=1;len<n;len<<=1){
int cnt=0;
F(i,n-len+1,n)sec[++cnt]=i;
F(i,1,n)if(sa[i]>len)sec[++cnt]=sa[i]-len;
memset(t,0,sizeof(t));
F(i,1,n)t[fir[i]]++;
F(i,1,max(122,n))t[i]+=t[i-1];
Fd(i,n,1)sa[t[fir[sec[i]]]--]=sec[i],sec[i]=0;
swap(fir,sec);
fir[sa[1]]=cnt=1;
F(i,2,n)fir[sa[i]]=(sec[sa[i]]==sec[sa[i-1]]&&sec[sa[i]+len]==sec[sa[i-1]+len]?cnt:++cnt);
if(cnt==n)break;
}
F(i,1,n)rk[sa[i]]=i;
int h=0;
F(i,1,n){
if(rk[i]==1)continue;
if(h)h--;
while(s[sa[rk[i]-1]+h]==s[i+h])h++;
height[rk[i]]=h;
}
}
}t;
适用范围:统计不同子串个数,LCS,LCP,多次出现的子串
Problems:
6.PAM
https://www.cnblogs.com/nianheng/p/9814530.html
struct PAM{
int son[N][26],len[N],s[N],fail[N],tot,last,n;
LL size[N];
int getfail(int p,int x){while(ch[p]!=ch[p-len[x]-1])x=fail[x];return x;}
void build(){
scanf("%s",ch+1);
n=strlen(ch+1);
last=tot=fail[0]=fail[1]=1;
len[1]=-1;
F(i,1,n){
int now=getfail(i,last);
if(!son[now][ch[i]-'A']){
tot++;
fail[tot]=son[getfail(i,fail[now])][ch[i]-'A'];
son[now][ch[i]-'A']=tot;
len[tot]=len[now]+2;
}
size[son[now][ch[i]-'A']]++;
last=son[now][ch[i]-'A'];
}
Fd(i,tot,2)size[fail[i]]+=size[i];
}
}P;
适用范围:统计回文串个数,回文串出现次数
Problems:
7.SAM
https://oi-wiki.org/string/sam/
struct SAM{
int ch[N][26],len[N],link[N],tot,rt,last;
void build(){
scanf("%s",s+1);
n=strlen(s+1);
rt=tot=last=1;
F(i,1,n){
int u=++tot,v=last,pos=s[i]-'a';
for(;v&&!ch[v][pos];v=link[v])ch[v][pos]=u,len[u]=max(len[u],len[v]+1);
if(!v)link[u]=rt;
else if(len[v]+1==len[ch[v][pos]])link[u]=ch[v][pos];
else{
int Old=ch[v][pos],clone=++tot;
len[clone]=len[v]+1;
F(j,0,25)ch[clone][j]=ch[Old][j];
link[clone]=link[Old];
link[Old]=link[u]=clone;
for(;v&&ch[v][pos]==Old;v=link[v])ch[v][pos]=clone;
}
}
}
}S;
适用范围:统计字串个数,统计字串长度和,匹配(出现)类问题
Problems:

浙公网安备 33010602011771号