P5496-[模板]回文自动机【PAM】

正题

题目链接:https://www.luogu.com.cn/problem/P5496


题目大意

长度为 n n 的字符串,求每个字符串作为结尾有多少个回文串。


解题思路

P A M PAM

下面是个人对 P A M PAM 的一些理解(不是讲解):

  1. 每个节点表示一个回文串,就是根到其的路径上的字符为一半。
  2. 为了方便表示长度为奇数的和偶数的,这里用了两个根节点。一个奇数根长度为 1 -1 ,偶数根长度为 0 0 。偶数根的 f a i l fail 指向奇数根。
  3. f a i l fail 指针表示该回文串的最长回文后缀(不包括整串)
  4. 加入新节点时,在上个节点的基础上不停的往后跳 f a i l fail 直到该回文串的前一个字符等于当且字符。
  5. 新节点的 f a i l fail 值同理在新点的父节点的 f a i l fail 上面跳 f a i l fail
  6. 时间复杂度 O ( n ) O(n) ,空间复杂度 O ( n T ) O(nT)

c o d e code

#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()]);
	}
}
发布了867 篇原创文章 · 获赞 55 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/Mr_wuyongcong/article/details/104087516