构造一种fail向同一个节点的回文机:
abadabacaba
这样caba和daba都会指向ba。
带展示功能的回文自动机:
#include <bits/stdc++.h> using namespace std; typedef long long ll; struct Node { int len, ch[26], fail; int cnt; string str; Node(int len = 0) : len(len), fail(0) { memset(ch, 0, sizeof(ch)); //下面是维护额外信息 cnt = 0; str=""; } void show() { printf(" str=\"%s\"\n", str.c_str()); printf(" len=%d cnt=%d\n",len,cnt); } }; const int MAXN = 600000; //PalindromicAutomaton struct PAM { Node nd[MAXN + 5]; int len, top, last; // len为字符串长度,top为节点个数,last为最后插入字符所对应的节点 char s[MAXN + 5]; string ls; //用来展示的辅助字符串 int getfail(int x) { //沿着fail指针找到第一个回文后缀 while(s[len - nd[x].len - 1] != s[len]) x = nd[x].fail; return x; } void init() { len = 0, top = 0, last = 0; nd[top] = Node(0); nd[top].fail = 1; nd[++top] = Node(-1); nd[top].fail = 0; s[0] = '$'; } void extend(char c) { s[++len] = c; int now = getfail(last); //找到插入的位置 ls = nd[now].str + c; //用来展示的辅助字符串 if(!nd[now].ch[c - 'a']) { //若没有这个节点,则新建并求出它的fail指针 nd[++top] = Node(nd[now].len + 2); nd[top].fail = nd[getfail(nd[now].fail)].ch[c - 'a']; nd[now].ch[c - 'a'] = top; } last = nd[now].ch[c - 'a']; nd[last].str = ls; //用来展示的辅助字符串 //下面是维护额外信息 ++nd[last].cnt; } void show() { for(int i = top; i >= 0; --i) { printf("node: id=%d\n", i); nd[i].show(); printf("fail: id=%d\n", nd[i].fail); nd[nd[i].fail].show(); puts(""); } } } pam; char s[MAXN + 5]; ll ans[MAXN + 5]; int main() { #ifdef Yinku freopen("Yinku.in", "r", stdin); #endif // Yinku while(~scanf("%s", s)) { int n = strlen(s); pam.init(); for(int i = 0; s[i] != '\0'; ++i) pam.extend(s[i]); //pam.show(); for(int i = pam.top; i >= 2; --i) { Node *now = &pam.nd[i]; Node *fail = &pam.nd[now->fail]; fail->cnt += now->cnt; } pam.show(); } return 0; }
来源:https://www.cnblogs.com/Yinku/p/11243179.html