P3804 [模板]后缀自动机 题解
拆出来的点贡献为 \(0\),其他贡献为 \(1\),在 DAWG 上统计一个后缀和即可。
点击查看代码
const int N=1e6+13,M=26;
int n,len[N<<1],nxt[N<<1],ptot=1,lastpos=1,ind[N<<1];
ll cnt[N<<1];
std::array<int,M> son[N<<1],boom;
char s[N];
inline int newpos(std::array<int,M> nson,int nlen){return ++ptot,len[ptot]=nlen,swap(son[ptot],nson),ptot;}
inline void insert(int c){
int p=lastpos;int u=newpos(boom,len[p]+1);cnt[u]=1;
while(p&&!son[p][c]) son[p][c]=u,p=nxt[p];
if(!p) return lastpos=u,nxt[u]=1,void();
int d=son[p][c];
if(len[d]==len[p]+1) nxt[u]=d;
else{
int v=newpos(son[d],len[p]+1);
nxt[v]=nxt[d],nxt[d]=v,nxt[u]=v;
while(p&&son[p][c]==d) son[p][c]=v,p=nxt[p];
}
lastpos=u;
}
int main(){
#ifdef LOCAL
freopen("P3804_4.in","r",stdin);
#endif
read(s+1);n=strlen(s+1);
for(int i=1;i<=n;++i) insert(s[i]-'a');
for(int i=2;i<=ptot;++i) ind[nxt[i]]++;
std::queue<int> q;
for(int i=2;i<=ptot;++i)
if(!ind[i]) q.push(i);
while(!q.empty()){
int u=q.front();q.pop();
if(nxt[u]==1) continue;
cnt[nxt[u]]+=cnt[u];
if(!(--ind[nxt[u]])) q.push(nxt[u]);
}
ll ans=0;
for(int i=2;i<=ptot;++i)
if(cnt[i]>1) ans=max(ans,cnt[i]*len[i]);
println(ans);
return 0;
}