「Luogu P3804」【模板】后缀自动机

给定一个只用小写字母组成的串$S$,求出$S$中所有出现次数大于$1$的子串的出现次数与它的长度的乘积的最大值。

$\texttt{Data Range:}\vert S\vert \leq 10^6$

链接

Luogu P3804

题解

首先把后缀自动机建出来,然后考虑对每个自动机上的节点求一遍$\texttt{size}$,答案就是$\max\{len\times size\}$啦qwq

顺便说一句,这种方法会在后面的文章上频繁使用,注意!

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include<bits/stdc++.h>
using namespace std;
typedef int ll;
typedef long long int li;
const ll MAXN=2e6+51;
ll length,k,cur;
li res;
ll prefix[MAXN],barrel[MAXN],size[MAXN];
char str[MAXN];
inline ll read()
{
register ll num=0,neg=1;
register char ch=getchar();
while(!isdigit(ch)&&ch!='-')
{
ch=getchar();
}
if(ch=='-')
{
neg=-1;
ch=getchar();
}
while(isdigit(ch))
{
num=(num<<3)+(num<<1)+(ch-'0');
ch=getchar();
}
return num*neg;
}
namespace SuffixAutomaton{
const ll sigmaSize=27;
struct Node{
ll son[sigmaSize];
ll fa,length;
};
struct SuffixAutomaton{
Node nd[MAXN];
ll last,tot;
SuffixAutomaton()
{
last=tot=1;
}
inline void extend(ll ch)
{
ll p=last,nxt=++tot,nxt2,k;
last=nxt,nd[nxt].length=nd[p].length+1;
while(p&&!nd[p].son[ch])
{
nd[p].son[ch]=nxt,p=nd[p].fa;
}
if(!p)
{
nd[nxt].fa=1;
}
else
{
k=nd[p].son[ch];
if(nd[p].length+1==nd[k].length)
{
nd[nxt].fa=k;
}
else
{
nxt2=++tot,nd[nxt2]=nd[k];
nd[nxt2].length=nd[p].length+1,nd[k].fa=nd[nxt].fa=nxt2;
while(p&&nd[p].son[ch]==k)
{
nd[p].son[ch]=nxt2,p=nd[p].fa;
}
}
}
size[nxt]=1;
}
};
}
SuffixAutomaton::SuffixAutomaton sam;
int main()
{
scanf("%s",str+1);
length=strlen(str+1);
for(register int i=1;i<=length;i++)
{
sam.extend(str[i]-97);
}
k=sam.tot;
for(register int i=1;i<=k;i++)
{
prefix[sam.nd[i].length]++;
}
for(register int i=1;i<=k;i++)
{
prefix[i]+=prefix[i-1];
}
for(register int i=1;i<=k;i++)
{
barrel[prefix[sam.nd[i].length]--]=i;
}
for(register int i=k;i;i--)
{
cur=barrel[i];
size[sam.nd[cur].fa]+=size[cur];
if(size[cur]>1)
{
res=max(res,(li)size[cur]*sam.nd[cur].length);
}
}
printf("%lld",res);
}