Little Tip
这道题,千万不要看中文翻译!!!
我一开始就看的中文,看得我一脸懵逼,什么什么什么鬼啊
后来看了题解,还是一脸懵逼
再后来滚去看英文版本的,喔~~~
豁然开朗
不过既然都说到这个份上了
大家是不是都觉得我要翻译一下了啊
当然不是。
自己去翻。
英文还是蛮好懂的
分析
KMP是真的妙,一定要深入理解 n x t [ i ] nxt[i] nxt[i] 的含义
n x t [ i ] nxt[i] nxt[i] : 以 i i i作为结尾的,最长的,相同前后缀的长度
小栗子献上:
a
b
c
a
b
abcab
abcab 中
n
x
t
[
5
]
=
2
,
n
x
t
[
4
]
=
1
,
n
x
t
[
3
]
=
0
,
n
x
t
[
2
]
=
0
,
n
x
t
[
1
]
=
0
nxt[5]=2,nxt[4]=1,nxt[3]=0,nxt[2]=0,nxt[1]=0
nxt[5]=2,nxt[4]=1,nxt[3]=0,nxt[2]=0,nxt[1]=0
对于这道题,我们需要求串A的每一个前缀的最大周期之和
也就是求任意一个串的最大周期,然后相加
最大周期就是,,,我们先定义串B:满足B是A的一个前缀,且A是两倍B的前缀
最大周期就是串B的最大的长度
来看一张图
(图摘自洛谷)
我们发现
i
−
n
x
t
[
i
]
i-nxt[i]
i−nxt[i]就是一个周期,当
n
x
t
[
i
]
nxt[i]
nxt[i]最小的时候,求得的就是最大周期
这同时也满足了A是两倍串B的条件,为什么呢?
若
n
x
t
[
i
]
>
l
e
n
i
/
2
nxt[i]>leni/2
nxt[i]>leni/2,此时
i
−
n
x
t
[
i
]
<
l
e
n
i
/
2
i-nxt[i]<leni/2
i−nxt[i]<leni/2肯定是错误的
但由于我们始终是在找
n
x
t
[
i
]
nxt[i]
nxt[i]的最小值,当
n
x
t
[
i
]
>
l
e
n
i
/
2
nxt[i]>leni/2
nxt[i]>leni/2时,肯定还可以找到更小的
最后我们稍微优化一下
Code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
char st[1000009];
int nxt[1000009];
int main(){
int len,i,j;
scanf("%d",&len);
scanf("%s",st+1);
nxt[1]=0;j=0;
for(i=2;i<=len;++i){
while(j&&st[j+1]!=st[i]) j=nxt[j];
if(st[j+1]==st[i]) j++;
nxt[i]=j;
}
ll ans=0;
for(i=1;i<=len;++i){
j=i;
while(nxt[j]) j=nxt[j];
if(nxt[i]) nxt[i]=j;//优化
ans+=1ll*(i-j);
}
cout<<ans;
return 0;
}