也叫回文树
PAM可以处理出一个串的所有不同的回文串与它们的出现次数
回文树比较简单,每次执行 insert
操作后的状态节点都是以这个字母为结尾的后缀的最长回文串,fail
指针指的是长度小于它的下一个后缀回文串。
一个串的所有不同的回文子串就是回文树上的所有节点 - 2, 除了两个根节点
/*
* @Author: zhl
* @Date: 2020-11-24 11:57:26
*/
#include<bits/stdc++.h>
using namespace std;
const int N = 2e6 + 10;
struct Node {
int ch[26], fail;
int len, sum;
}tr[N];
char s[N];
int last, tot = 2;
int newnode(int len) {
tr[tot].len = len;
//tr[tot].fail = 0;
//for(int i = 0;i < 26;i++)tr[tot].ch[i] = 0;
return tot++;
}
int getFail(int x, int pos) {
while (s[pos - tr[x].len - 1] != s[pos]) x = tr[x].fail;
return x;
}
void init() {
tr[0].len = 0, tr[1].len = -1;
tr[0].fail = 1; tr[1].fail = 0;
//for(int i = 0;i < 26;i++)tr[0].ch[i] = tr[1].ch[i] = 0;
last = 0;
}
void insert(int pos) {
int cur = getFail(last, pos);
int c = s[pos] - 'a';
if (tr[cur].ch[c] == 0) {
int now = newnode(tr[cur].len + 2);
tr[now].fail = tr[getFail(tr[cur].fail, pos)].ch[c]; //fail指向后缀中的最长回文串
tr[now].sum = tr[tr[now].fail].sum + 1;
tr[cur].ch[c] = now;
}
last = tr[cur].ch[c];
}
int main() {
scanf("%s", s + 1);
int k = 0; int n = strlen(s + 1);
init();
for (int i = 1; i <= n; i++) {
s[i] = (s[i] - 97 + k) % 26 + 97;
insert(i);
printf("%d ", tr[last].sum);
k = tr[last].sum;
}
}