版权声明:虽然我只是个小蒟蒻但转载也请注明出处哦 https://blog.csdn.net/weixin_42557561/article/details/83414084
Little Tip
这道题,千万不要看中文翻译!!!
我一开始就看的中文,看得我一脸懵逼,什么什么什么鬼啊
后来看了题解,还是一脸懵逼
再后来滚去看英文版本的,喔~~~
豁然开朗
不过既然都说到这个份上了
大家是不是都觉得我要翻译一下了啊
当然不是。
自己去翻。
英文还是蛮好懂的
分析
KMP是真的妙,一定要深入理解 的含义
: 以 作为结尾的,最长的,相同前后缀的长度
小栗子献上:
中
对于这道题,我们需要求串A的每一个前缀的最大周期之和
也就是求任意一个串的最大周期,然后相加
最大周期就是,,,我们先定义串B:满足B是A的一个前缀,且A是两倍B的前缀
最大周期就是串B的最大的长度
来看一张图
(图摘自洛谷)
我们发现
就是一个周期,当
最小的时候,求得的就是最大周期
这同时也满足了A是两倍串B的条件,为什么呢?
若
,此时
肯定是错误的
但由于我们始终是在找
的最小值,当
时,肯定还可以找到更小的
最后我们稍微优化一下
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;
}