题目:51nod1277.
题目大意:给定一个长度为
n
n
n的串,求出它前缀的最大值,其中一个前缀的值定义为这个前缀在字符串中出现的次数乘以这个前缀的长度.
1
≤
n
≤
1
0
5
1\leq n\leq 10^5
1≤n≤105.
很明显一道字符串前缀相关的题,而且还是单串匹配,所以就是KMP了.
考虑先求出 n e x t next next数组,我们考虑一个前缀出现次数如何通过 n e x t next next数组计算.
这道题其实是要知道每个前缀的出现次数就可以了,所以我们记录一个 s u m sum sum数组,其中 s u m [ i ] sum[i] sum[i]表示前缀 S [ 1.. i ] S[1..i] S[1..i]在串中出现的次数.
考虑计算 s u m sum sum,我们可以发现前缀 s u m [ 1.. i ] sum[1..i] sum[1..i]对 s u m [ 1 n e x t [ i ] ] sum[1~next[i]] sum[1 next[i]]都有 1 1 1的贡献,但是这里如果直接用差分维护区间加貌似会重复计数.
既然直接求不行,那就考虑
s
u
m
[
i
]
sum[i]
sum[i]与其他
s
u
m
sum
sum值的关系,发现若
n
x
t
[
j
]
=
i
nxt[j]=i
nxt[j]=i,那么就是说所有
s
[
1..
j
]
s[1..j]
s[1..j]出现的地方都会出现
s
[
1..
i
]
s[1..i]
s[1..i].这提醒我们
s
u
m
[
i
]
sum[i]
sum[i]其实可以这样计算:
s
u
m
[
i
]
=
1
+
∑
n
e
x
t
[
j
]
=
i
s
u
m
[
j
]
sum[i]=1+\sum_{next[j]=i}sum[j]
sum[i]=1+next[j]=i∑sum[j]
所以我们只需要倒推解决这道题,可以做到 O ( n ) O(n) O(n),由此我们得到了这道题的解法.
其实我们可以用 n e x t next next树来解释上面这个式子,因为 n e x t next next树上一个节点是它所有子树的前缀,所以一个节点为根的子树中任意一个节点都会对它有贡献,这样这个式子就很好解释了.
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=1000000;
char a[N+9];
int n,nxt[N+9];
LL sum[N+9],ans;
void self_mate(){
nxt[1]=0;
int j=0;
for (int i=2;i<=n;++i){
while (a[i]^a[j+1]&&j>0) j=nxt[j];
if (a[j+1]==a[i]) ++j;
nxt[i]=j;
}
}
Abigail into(){
scanf("%s",a+1);
n=strlen(a+1);
}
Abigail work(){
self_mate();
for (int i=n;i>=1;--i){
++sum[i];
sum[nxt[i]]+=sum[i];
ans=max(ans,sum[i]*i);
}
}
Abigail outo(){
printf("%lld\n",ans);
}
int main(){
into();
work();
outo();
return 0;
}