正题
题目链接:https://www.luogu.com.cn/problem/P5496
题目大意
长度为 的字符串,求每个字符串作为结尾有多少个回文串。
解题思路
。
下面是个人对 的一些理解(不是讲解):
- 每个节点表示一个回文串,就是根到其的路径上的字符为一半。
- 为了方便表示长度为奇数的和偶数的,这里用了两个根节点。一个奇数根长度为 ,偶数根长度为 。偶数根的 指向奇数根。
- 指针表示该回文串的最长回文后缀(不包括整串)
- 加入新节点时,在上个节点的基础上不停的往后跳 直到该回文串的前一个字符等于当且字符。
- 新节点的 值同理在新点的父节点的 上面跳 。
- 时间复杂度 ,空间复杂度
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e6+10;
int n,len[N],fail[N],num[N],next[N][26],cnt,m,last;
char s[N];
int get_fail(int x){
for(;s[n-len[x]-1]!=s[n];)x=fail[x];
return x;
}
int Insert(){
int x=get_fail(last);
if(!next[x][s[n]]){
len[++cnt]=len[x]+2;
int y=get_fail(fail[x]);
fail[cnt]=next[y][s[n]];
num[cnt]=num[fail[cnt]]+1;
next[x][s[n]]=cnt;
}
return (last=next[x][s[n]]);
}
int main()
{
scanf("%s",s+1);
m=strlen(s+1);
s[0]=26;
len[1]=-1;fail[0]=cnt=1;
int k=0;
for(n=1;n<=m;n++){
s[n]=(s[n]-'a'+k)%26;
printf("%d ",k=num[Insert()]);
}
}