这是一篇偷懒的文章,主要是今天确实碰到了比较难理解的数据结构。
之前是以为所有的后缀自动机都可以用后缀数组代替的,今天做到有一道题hdu6405,似乎并非如此了,主要这题是多串的,所以没法子后缀数组,只能后缀自动机(而且还是广义后缀自动机,相关题解明天补上)
今天参考的博文
传送门A
传送门B
传送门C
相关的理解和思考以及应用,以后会补上。
附上我的模板(其实是抄传送门A的),当然这题可以用后缀数组做。
//给定一个只包含小写字母的字符串SS,
//请你求出 SS 的所有出现次数不为 1 的子串的出现次数乘上该子串长度的最大值。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
using LL=long long;
const int N=1E6+5,M=2E6+10;
char s[N];
int cur,cnt,n,last,ch[M][26],lnk[M],dis[M],sz[M],c[N],sa[M];
LL ans;
void build_sam(int c, int id)
{
last=cur;
cur=++cnt;
int p=last;
dis[cur]=id;
for(;p&&!ch[p][c];p=lnk[p])
ch[p][c]=cur;
if(!p)
lnk[cur]=1;
else
{
int q=ch[p][c];
if(dis[q]==dis[p]+1)
lnk[cur]=q;
else
{
int nt=++cnt;
dis[nt]=dis[p]+1;
memcpy(ch[nt],ch[q],sizeof(ch[q]));
lnk[nt]=lnk[q];
lnk[q]=lnk[cur]=nt;
for(;ch[p][c]==q;p=lnk[p])
ch[p][c]=nt;
}
}
sz[cur]=1;
}
void Flower()
{
for(int i=1;i<=cnt;i++)
c[dis[i]]++;
for(int i=1;i<=n;i++)
c[i]+=c[i-1];
for(int i=cnt;i;i--)
sa[c[dis[i]]--]=i; //技巧:相当于dis从大到小排序(这是dp顺序),比nlogn快那么点
for(int i=cnt;i;i--)
{
int p=sa[i];
if(sz[p]>1)
ans=max(ans,(LL)sz[p]*dis[p]); //dp
sz[lnk[p]]+=sz[p]; //dp
}
}
int main()
{
scanf("%s",s+1);
n=strlen(s+1);
cur=cnt=1;
for(int i=1;i<=n;i++)
build_sam(s[i]-'a',i);
Flower();
printf("%lld",ans);
return 0;
}