字符串算法复习
声明:
由于本人较弱,并不能保证以下内容的100%正确
欢迎大佬来挑错
Hash
自然溢出hash
单模数hash
双模数hash
挂链hash
Trie
普通Trie
可持久化Trie
Kmp
扩展Kmp(不会)
后缀数组
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cassert> 5 using namespace std; 6 const int maxn=1000009; 7 8 int n; 9 10 char s[maxn]; 11 int sa[maxn],c[maxn]; 12 int t1[maxn<<1],t2[maxn<<1]; 13 void BuildSA(int m){ 14 int *x=t1,*y=t2; 15 16 for(int i=1;i<=m;++i)c[i]=0; 17 for(int i=1;i<=n;++i)c[x[i]=s[i]]++; 18 for(int i=2;i<=m;++i)c[i]+=c[i-1]; 19 for(int i=n;i>=1;--i)sa[c[x[i]]--]=i; 20 21 for(int k=1;k<n;k<<=1){ 22 int p=0; 23 for(int i=n-k+1;i<=n;++i)y[++p]=i; 24 for(int i=1;i<=n;++i)if(sa[i]-k>0)y[++p]=sa[i]-k; 25 26 for(int i=1;i<=m;++i)c[i]=0; 27 for(int i=1;i<=n;++i)c[x[y[i]]]++; 28 for(int i=2;i<=m;++i)c[i]+=c[i-1]; 29 for(int i=n;i>=1;--i)sa[c[x[y[i]]]--]=y[i]; 30 31 swap(x,y); 32 x[sa[1]]=p=1; 33 for(int i=2;i<=n;++i){ 34 if((y[sa[i]]==y[sa[i-1]])&&(y[sa[i]+k]==y[sa[i-1]+k]))x[sa[i]]=p; 35 else x[sa[i]]=++p; 36 } 37 if(p>=n)break; 38 m=p; 39 } 40 } 41 42 int main(){ 43 scanf("%s",s+1); 44 n=strlen(s+1); 45 BuildSA(10000); 46 47 for(int i=1;i<=n;++i)printf("%d ",sa[i]); 48 return 0; 49 }
后缀自动机
Menci的链接
https://oi.men.ci/suffix-automaton-notes/
写得很清楚
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 const int maxn=1000009; 6 7 8 int n; 9 long long ans=0; 10 char s[maxn]; 11 12 int nn=1,last=1; 13 int par[maxn<<1]={0}; 14 int siz[maxn<<1]={0}; 15 int dis[maxn<<1]={0}; 16 int ch[maxn<<1][26]={0}; 17 void BuildSAM(int c){ 18 int p=last,np=++nn; 19 last=np;siz[np]=1;dis[np]=dis[p]+1; 20 21 for(;(p!=0)&&(!ch[p][c]);p=par[p])ch[p][c]=np; 22 if(!p){ 23 par[np]=1; 24 }else{ 25 int q=ch[p][c]; 26 if(dis[q]==dis[p]+1){ 27 par[np]=q; 28 }else{ 29 int nq=++nn; 30 for(int i=0;i<26;++i)ch[nq][i]=ch[q][i]; 31 dis[nq]=dis[p]+1; 32 par[nq]=par[q]; 33 par[q]=par[np]=nq; 34 for(;ch[p][c]==q;p=par[p])ch[p][c]=nq; 35 } 36 } 37 } 38 39 int c[maxn<<1]; 40 int sa[maxn<<1]; 41 void Dp(){ 42 for(int i=1;i<=nn;++i)c[dis[i]]++; 43 for(int i=1;i<=nn;++i)c[i]+=c[i-1]; 44 for(int i=1;i<=nn;++i)sa[c[dis[i]]--]=i; 45 for(int i=nn;i>=1;--i){ 46 int x=sa[i]; 47 siz[par[x]]+=siz[x]; 48 if(siz[x]!=1){ 49 ans=max(ans,1LL*siz[x]*dis[x]); 50 } 51 } 52 } 53 54 int main(){ 55 scanf("%s",s+1); 56 n=strlen(s+1); 57 for(int i=1;i<=n;++i)BuildSAM(s[i]-'a'); 58 59 Dp(); 60 cout<<ans<<endl; 61 return 0; 62 }
广义后缀自动机
2780: [Spoj]8093 Sevenk Love Oimaster
4566: [Haoi2016]找相同字符
AC自动机
2754: [SCOI2012]喵星球上的点名
manacher
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 const int maxn=30000000; 6 7 int n; 8 int ans=0; 9 char T[maxn]; 10 11 char s[maxn]; 12 int p[maxn]; 13 void Manacher(int n){ 14 int mxpla=0,mxlen=0; 15 for(int i=1;i<=n;++i){ 16 if(mxpla+mxlen>i){ 17 p[i]=min(mxpla+mxlen-i,p[2*mxpla-i]); 18 } 19 while(s[i-p[i]]==s[i+p[i]])++p[i]; 20 ans=max(ans,p[i]*2-1); 21 if(i+p[i]>mxpla+mxlen){ 22 mxpla=i;mxlen=p[i]; 23 } 24 } 25 } 26 27 int main(){ 28 scanf("%s",T+1); 29 n=strlen(T+1); 30 int len=0; 31 s[++len]='*'; 32 for(int i=1;i<=n;++i){ 33 s[++len]=T[i]; 34 s[++len]='*'; 35 } 36 s[++len]='#'; 37 Manacher(len); 38 39 cout<<(ans>>1)<<endl; 40 return 0; 41 }