模板 - 回文自动机
构造一种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;
}