字符串-后缀自动机
学了好久啊。
基本定义看洛谷日报就好啦。
大概就是走DAG的边相当于添加字符,跳parent树的边相当于删除一段前缀。这样就好理解了。
如果想要得到后缀树,考虑对反串建后缀自动机然后记录endpos(或称right)集中的一个元素,就得到了parent树上边的信息。其实没什么用,万一题目要求输出字符串呢。
板子也自己去看叭
算了还是放一份板子吧
#include<bits/stdc++.h> using namespace std; const int N=1e6+6; const int Z=128-' '; int f[N<<1],c[N<<1][Z],l[N<<1]; int tb[N<<1],ep[N<<1]; int pr=1,cnt=1; void ins(int x){ int p=pr,v=pr=++cnt; l[v]=l[p]+1; ep[v]=tb[v]=l[v]; for(;p&&!c[p][x];p=f[p])c[p][x]=v; if(!p)f[v]=1; else{ int u=c[p][x]; if(l[u]==l[p]+1)f[v]=u; else{ int w=++cnt; f[w]=f[u]; ep[w]=ep[u]; for(int i=0;i<Z;i++)c[w][i]=c[u][i]; l[w]=l[p]+1; f[u]=f[v]=w; for(;p&&c[p][x]==u;p=f[p])c[p][x]=w; } } } vector<int>e[N<<1]; int t[N][Z]; void dfs(int v){ for(int i=0;i<e[v].size();i++){ dfs(e[v][i]); ep[v]=ep[e[v][i]]; } } void dfs2(int v){ if(tb[v])printf("%d ",tb[v]); for(int i=0;i<Z;i++) if(t[v][i])dfs2(t[v][i]); } char s[N]; int main() { scanf("%s",s+1); int n=strlen(s+1),i; for(i=n;i;i--) ins(s[i]-' '); for(i=2;i<=cnt;i++) if(tb[i])tb[i]=n+1-tb[i]; for(i=2;i<=cnt;i++) e[f[i]].push_back(i); dfs(1); for(i=2;i<=cnt;i++) t[f[i]][s[n+1-(ep[i]-l[f[i]])]-' ']=i; dfs2(1); return 0; }
这是SA板子题,会MLE几个点。
SAM板子题当然要用SA来写啦
#include<bits/stdc++.h> using namespace std; typedef long long i64; const int N=1e6+6; char s[N]; int t1[N],t2[N],c[N]; int sa[N],rk[N],ht[N]; void gtsa(int n,int m){ int *x=t1,*y=t2,i,j,p=0; for(i=1;i<=n;i++)++c[x[i]=s[i]]; for(i=1;i<=m;i++)c[i]+=c[i-1]; for(i=n;i;i--)sa[c[x[i]]--]=i; for(j=1;j<=n&&p<n;j<<=1){ p=0; for(i=n-j+1;i<=n;i++)y[++p]=i; for(i=1;i<=n;i++)if(sa[i]>j)y[++p]=sa[i]-j; for(i=1;i<=m;i++)c[i]=0; for(i=1;i<=n;i++)++c[x[y[i]]]; for(i=1;i<=m;i++)c[i]+=c[i-1]; for(i=n;i;i--)sa[c[x[y[i]]]--]=y[i]; swap(x,y); p=1;x[sa[1]]=1; for(i=2;i<=n;i++) x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j]?p:++p; m=p; } for(i=1;i<=n;i++)rk[sa[i]]=i; p=1; for(i=1;i<=n;i++){ j=sa[rk[i]-1]; if(p)--p; while(s[i+p]==s[j+p])++p; ht[rk[i]]=p; } } int b[N],h[N],tp; int main() { scanf("%s",s+1); int n=strlen(s+1); gtsa(n,127); tp=0; i64 ans=0; int i,nb; for(i=1;i<=n;i++){ nb=i; while(h[tp]>ht[i+1])ans=max(ans,1ll*(i-b[tp]+1)*h[tp]),nb=b[tp],--tp; ++tp;b[tp]=nb;h[tp]=ht[i+1]; } printf("%lld",ans); return 0; }

浙公网安备 33010602011771号