回文自动机 PAM

也叫回文树

PAM可以处理出一个串的所有不同的回文串与它们的出现次数

回文树比较简单,每次执行 insert 操作后的状态节点都是以这个字母为结尾的后缀的最长回文串,fail指针指的是长度小于它的下一个后缀回文串。

一个串的所有不同的回文子串就是回文树上的所有节点 - 2, 除了两个根节点

P5496 【模板】回文自动机(PAM) - 洛谷

/*
 * @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;
	}
}
原文地址:https://www.cnblogs.com/sduwh/p/14036106.html