題目鏈接: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); }