正题
题目链接:https://www.luogu.com.cn/problem/P3804
题目大意
长度为 的串,求一个出现次数不小于2的子串使得子串长度乘上出现次数最大。
解题思路
构建 的时候统计一下每个子串出现多少次即可。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e6+10;
int n,cnt,num[N],len[N],fail[N],next[N][26],ans;
char s[N];
void New_Point(int x,int y){
next[x][y]=++cnt;
len[cnt]=len[x]+1;
}
void Make_SAM(char *s){
int last;
cnt=last=num[1]=1;
for(int i=1;i<=n;i++){
int val=s[i]-'a';
New_Point(last,val);
int x=last,y;last=next[x][val];
for(y=fail[x];y;y=fail[y])
if(!next[y][val]) next[y][val]=last;
else{
if(len[y]+1==len[next[y][val]])
fail[last]=next[y][val];
else{
int z=next[y][val];
New_Point(y,val);
fail[cnt]=fail[z];
num[cnt]=num[z];
fail[last]=fail[z]=cnt;
for(int i=0;i<26;i++)
next[cnt][i]=next[z][i];
for(int w=y;w;w=fail[w])
if(next[w][val]==z)
next[w][val]=cnt;
}
break;
}
if(!y)fail[last]=1;
for(y=last;y;y=fail[y])
num[y]++;
}
return;
}
int main()
{
scanf("%s",s+1);
n=strlen(s+1);
Make_SAM(s);
for(int i=1;i<=cnt;i++)
if(num[i]>1)
ans=max(ans,num[i]*len[i]);
printf("%d",ans);
}