后缀自动机模板题.
关键时求解每个节点的 $right$ 大小.
由于后缀自动机在构建时会保证点和点的 $right$ 只可能没有交集,或者一个是另一个的真子集,我们可以不重复的对 $right$ 进行统计与更新.
从长度大的子串向前更新,沿着 $parent$ 跳即可.
最后再枚举一下.
Code:
#include <cstdio> #include <algorithm> #include <cstring> #define setIO(s) freopen(s".in","r",stdin) #define maxn 3000000 #define N 30 #define ll long long using namespace std; int last=1,tot=1,n; int ch[maxn][N],cnt[maxn],f[maxn],dis[maxn],rk[maxn]; ll C[maxn],ans; char str[maxn]; struct Suffix_Automaton{ void ins(int c){ int p=last,np=++tot; last=np; dis[np]=dis[p]+1; while(p&&!ch[p][c])ch[p][c]=np,p=f[p]; if(!p) f[np]=1; else{ int q=ch[p][c],nq; if(dis[q]==dis[p]+1) f[np]=q; else{ nq=++tot; dis[nq]=dis[p]+1; memcpy(ch[nq],ch[q],sizeof(ch[q])); f[nq]=f[q],f[q]=f[np]=nq; while(p&&ch[p][c]==q) ch[p][c]=nq,p=f[p]; } } cnt[last]=1; } }sam; int main(){ //setIO("input"); scanf("%s",str),n=strlen(str); for(int i=0;i<n;++i) sam.ins(str[i]-'a'); for(int i=1;i<=tot;++i) ++C[dis[i]]; for(int i=1;i<=tot;++i) C[i]+=C[i-1]; for(int i=1;i<=tot;++i) rk[C[dis[i]]--]=i; for(int i=tot;i>=1;--i){ int p=rk[i]; cnt[f[p]]+=cnt[p]; if(cnt[p]>1) ans=max(ans,(ll)cnt[p]*dis[p]); } printf("%lld",ans); return 0; }