具体理解看博客就可以了
下面是一些数组的定义,这是必须要记住的
每个结点i表示从根到结点i路径上字符链代表的回文串
int fail[];//类似ac自动机的失配指针
int cnt[];//当前结点表示的回文串在原串中出现次数
int num[];//结点i可以向前fail的次数,也可以看作结点i作为右端点可代表的回文串后缀
int len[];//结点i代表的串的长度
int n;//插入字符长度
int p;//结点个数,出去两个初始结点,剩下的结点数就是串中本质不同的回文串的个数
#include <bits/stdc++.h> using namespace std; const int MAX = 512345; const int ALP = 26; struct Palindromic_Tree { int son[MAX][ALP]; //转移边 int fail[MAX]; //fail 指针 int cnt[MAX]; //当前节点表示的回文串在原串中出现了多少次 int num[MAX]; //当前节点 fail 可以向前跳多少次 int len[MAX]; //当前节点表示的回文串的长度 int S[MAX]; //插入的字符串 int last; //最后一次访问到的节点,类似 SAM int n; //插入的字符串长度 int p; //自动机的总状态数 int newnode(int l) { memset(son[p], 0, sizeof(son[p])); cnt[p] = 0; num[p] = 0; len[p] = l; return p++; } void init() { p = 0; newnode(0); newnode(-1); last = 0; n = 0; S[n] = -1; fail[0] = 1; } int get_fail(int x) { while (S[n - len[x] - 1] != S[n]) x = fail[x]; return x; } void add(int c) { c -= 'a'; S[++n] = c; int cur = get_fail(last); //通过上一次访问的位置去扩展 if (!son[cur][c]) { //如果没有对应的节点添加一个新节点 int now = newnode(len[cur] + 2); fail[now] = son[get_fail(fail[cur])][c]; //通过当前节点的 fail 去扩展出新的 fail son[cur][c] = now; num[now] = num[fail[now]] + 1; //记录 fail 跳多少次 } last = son[cur][c]; cnt[last]++; //表示当前节点访问了一次 } void count() { //如果某个节点出现一次,那么他的 fail 也一定会出现一次,并且在插入的时候没有计数 for (int i = p - 1; i >= 0; i--) cnt[fail[i]] += cnt[i]; } } AUT; char data[MAX]; int n; int main() { scanf("%s", data); n = strlen(data); AUT.init(); for (int i = 0; i < n; i++) AUT.add(data[i]); AUT.count(); long long ans = 0; for (int i = 0; i < AUT.p; i++) { ans = max(ans, 1ll * AUT.len[i] * AUT.cnt[i]); } printf("%lld ", ans); }