推荐一篇dalao写的博客:wind_whisper
题意
题解
首先想想题里说的周期和kmp里的 nxt 数组有没有什么关系
对于一个长度为 i 的串,i - nxt[i]就是一个周期的长度(不一定最大)
假设 i - nxt[i] > i/2 ,即一个串的最短(前缀=后缀)的长度一定小于等于这个串的一半
可以想象,把一个串的 1 ~ i - nxt[i] 的部分复制一倍接在后面,一定能使原来的整串成为新的串的前缀
但是 i - nxt[i] <i/2 的话,显然长度上就不满足,但这种情况(即一个串的最短(前缀=后缀)的长度一大于这个串的一半)是不存在的,具体见下图
(假设黑色的部分是最短的(前缀=后缀),就能证明出还存在更短的红色部分(前缀=后缀))
同时,这里连续跳 nxt 数组的过程可以用类似并查集路径压缩的方式优化,值得学习
代码
周期长度和
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int INF = 0x3f3f3f3f,N = 1e6+10;
int nxt[N],n;
ll ans;
char s[N];
void pre()
{
int j=0;
nxt[1]=0;
for(int i=1;i<n;i++)
{
while(s[i+1]!=s[j+1]&&j) j=nxt[j];
if(s[i+1]==s[j+1]) j++;
nxt[i+1]=j;
}
}
int find(int x)
{
if(nxt[x]) return nxt[x]=find(nxt[x]);
return x;
int main()
{
scanf("%d%s",&n,s+1);
pre();
for(int i=1;i<=n;i++)
ans+=i-find(i);
//(我原本从nxt[i]开始错了)从i开始,因为当nxt[i]==0时没有周期
printf("%lld",ans);
return 0;
}