每个子串的出现次数就是其后缀自动机上所在节点的endpos等价类集合的大小。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=3000009;
char s[N];
int n;
struct Suffix_DFA
{
int Siz,last;
struct Dot
{
int len,link,ch[30],end;
}sam[N];
int head[N],cnt,Ans;
struct Edge
{
int nxt,to;
}g[N*2];
void add(int from,int to)
{
g[++cnt].nxt=head[from];
g[cnt].to=to;
head[from]=cnt;
}
void init()
{
sam[0].link=-1;
}
void SAM_Extend(int k)
{
int cur=++Siz;
sam[cur].len=sam[last].len+1,sam[cur].end=1;
int p=last;
while(p!=-1&&!sam[p].ch[k])
sam[p].ch[k]=cur,
p=sam[p].link;
if(p==-1)
sam[cur].link=0;
else
{
int q=sam[p].ch[k];
if(sam[q].len==sam[p].len+1)
sam[cur].link=q;
else
{
int clone=++Siz;
sam[clone].len=sam[p].len+1;
sam[clone].link=sam[q].link;
for (int i=1;i<=26;i++)
sam[clone].ch[i]=sam[q].ch[i];
while(p!=-1&&sam[p].ch[k]==q)
sam[p].ch[k]=clone,
p=sam[p].link;
sam[q].link=sam[cur].link=clone;
}
}
last=cur;
}
void build()
{
for (int i=1;i<=Siz;i++)
add(sam[i].link,i);
}
void dfs(int x)
{
for (int i=head[x];i;i=g[i].nxt)
{
int v=g[i].to;
dfs(v);
sam[x].end+=sam[v].end;
}
Ans=max(Ans,(sam[x].end==1?0:sam[x].end)*sam[x].len);
}
int Get_Ans()
{
build(),dfs(0);
return Ans;
}
}A;
void init()
{
scanf("%s",s+1);
}
void work()
{
n=strlen(s+1),A.init();
for (int i=1;i<=n;i++)
A.SAM_Extend(s[i]-'a'+1);
printf("%d
",A.Get_Ans());
}
int main()
{
init();
work();
return 0;
}