题目链接:https://www.luogu.org/problem/P3649
回文树的作用:
- 求串S前缀0~i内本质不同回文串的个数
- 求串S内每一个本质不同回文串出现的次数
- 求串S内回文串的个数(其实就是1和2结合起来)
- 求以下标i结尾的回文串的个数
#include<bits/stdc++.h> #define M 300010 using namespace std; char S[M]; int tot,last; struct plalindrome_tire { int len,fail,cnt,ch[26]; //fail指向最长后缀回文,len当前点构成最长回文长度,cnt回文出现次数,ch树的节点a~z } T[M]; int get_fail(int x,int n)//返回与点n构成最长回文的位置 { while(S[n-T[x].len-1]!=S[n]) x=T[x].fail; return x; } int main() { scanf("%s",S+1); //初始化 T[0].len=0,T[1].len=-1; T[0].fail=1; tot=1,last=0; for(int i=1; S[i]; ++i) { int id=S[i]-'a'; int cur=get_fail(last,i); if(!T[cur].ch[id]) { int v=++tot; T[v].len=T[cur].len+2; T[v].fail=T[get_fail(T[cur].fail,i)].ch[id]; T[cur].ch[id]=v; } last=T[cur].ch[id]; T[last].cnt++; } long long ans=0; for(int i=tot; i; --i)//最长回文中还有回文,需要从叶子节点倒着加回去,计算所有回文串个数 { T[T[i].fail].cnt+=T[i].cnt; ans=max(ans,1ll*T[i].len*T[i].cnt); } printf("%lld\n",ans); }