题目
求回文子串个数
题解
回文自动机是个好东西,可惜我不会(逃
回文自动机
不同于其他学过的自动机,回文自动机是两棵树组成的
一棵奇数树,一棵偶数树,可以理解?
内容
同样,每个节点代表一种状态。
基础维护的东西有:
l
e
n
i
当
前
节
点
对
应
的
状
态
长
s
u
m
i
当
前
节
点
对
应
状
态
的
出
现
次
数
f
a
i
l
i
当
前
节
点
对
应
状
态
的
最
大
后
缀
回
文
串
对
应
节
点
c
h
i
,
j
表
示
状
态
转
移
(
和
其
他
自
动
机
相
同
)
len_i当前节点对应的状态长 \\ sum_i当前节点对应状态的出现次数\\ fail_i \ 当前节点对应状态 的\ 最大后缀回文串对应节点\\ ch_{i,j}表示状态转移(和其他自动机相同)
leni当前节点对应的状态长sumi当前节点对应状态的出现次数faili 当前节点对应状态的 最大后缀回文串对应节点chi,j表示状态转移(和其他自动机相同)
初始化
偶 树 的 根 节 点 是 0 , l e n 0 = 0 , f a i l 0 = 0 ( 偶 数 偶 树 。 。 。 ) 奇 树 的 根 节 点 是 1 , l e n 1 = − 1 , f a i l 1 = 1 偶树的根节点是0,len_0=0\ \ \ ,fail_0=0(偶数偶树。。。)\\ 奇树的根节点是1,len_1=-1,fail_1=1 偶树的根节点是0,len0=0 ,fail0=0(偶数偶树。。。)奇树的根节点是1,len1=−1,fail1=1
基础操作:
get_fail(x,pos)
x代表节点,pos代表字符串的一个位置
找到pos最大能与 x哪个后缀回文串 组成新的回文串
int get_fail(int x,int pos)
{
while(s[pos-len[x]-1]!=s[pos])x=fail[x];//手推一下很容易理解
return x;
}
加点insert(pos)
1.之前有这个状态就不用新加了
2.新节点是旧节点
l
e
n
+
2
len+2
len+2,因为是回文(旧节点就是新节点要连的地方)
3.新节点的最大后缀回文,就是旧节点的最大后缀回文?不,应为 旧节点的最大后缀回文串的子串 且能与 新节点 能组成新回文
4.sum累计
5.pre更新,用来之后加入新节点
int make_new(int l)
{
++cnt;
len[cnt]=l;
return cnt;//其实这个都不用另开函数
}
void insert(int pos)
{
int cur=get_fail(pre,pos),st=s[pos]-'a';
if(!ch[cur][st])//原森林没有这个点就要新建
{
int now=make_new(len[cur]+2);
fail[now]=ch[get_fail(fail[cur],pos)][st];//3.
sum[now]=sum[fail[now]]+1;
ch[cur][st]=now;
}
pre=ch[cur][st];
}
本人刚学,自己总结,以后有空补补(或者就弃坑了)
//P5496的丢人代码
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
int n,pre;
char s[N];
int fail[N],len[N],sum[N];
int ch[N][30],cnt=1;
void init()
{
len[0]=0;len[1]=-1;
fail[0]=1;fail[1]=0;
pre=0;
}
int make_new(int l)
{
++cnt;
len[cnt]=l;
return cnt;
}
int get_fail(int x,int pos)
{
while(s[pos-len[x]-1]!=s[pos])x=fail[x];
return x;
}
void insert(int pos)
{
int cur=get_fail(pre,pos),st=s[pos]-'a';
if(!ch[cur][st])
{
int now=make_new(len[cur]+2);
fail[now]=ch[get_fail(fail[cur],pos)][st];
sum[now]=sum[fail[now]]+1;
ch[cur][st]=now;
}
pre=ch[cur][st];
}
int main()
{
int last=0;
init();
scanf("%s",s+1);n=strlen(s+1);
for(int i=1;s[i];i++)
{
s[i]=(s[i]-97+last)%26+97;
insert(i);
printf("%d ",last=sum[pre]);
}
}