版权声明:本文为博主原创文章,转载时请标明出处。 https://blog.csdn.net/FarmerJohnOfZS/article/details/81006479
构造方法
思考如何表示一个回文子串
记录其长度 len 和出现次数 cnt
由于每个子串可以表示成另一个回文串在两边各添加一个字符 c
那么 考虑构造一棵回文树 表示所有出现的回文子串
使用增量法 考虑已经构造了 S 的回文树 现在添加字符c 构造 Sc
我们需要找到以 c 结尾的最长回文子串 设末尾为 cMc
发现 M 为 S 的最长回文后缀 其(最长回文后缀)指针记作fail[S]
如何求得 cMc 的 fail ? 继续在M中重复寻找合法fail即可
由 manacher 正确性可知 点数最多为 O(n)
Code
char s[N];
struct pali{
int sz,cnt[N];
int to[N][26],fail[N];
int len[N],ln,las;
int st[N];
int gf(int x){while(st[ln-len[x]-1]!=st[ln])x=fail[x];return(x);}//getfail 即x点最长回文后缀
void add(int x)
{
st[++las]=x;int p=gf(las);//p代表文中M点
if(!to[p][x]) len[++sz]=len[p]+2,fail[sz]=to[gf(fail[p])][x],to[p][x]=sz;
++cnt[las=to[p][x]];//子串出现次数 注意要累加给其包含串 因为此时只计算了最长一个
}
void init()
{
len[sz=1]=-1;
fail[0]=1;
st[0]=-1;
las=0;
}
}