1. 程式人生 > >【BZOJ2342】雙倍回文(回文樹)

【BZOJ2342】雙倍回文(回文樹)

geo max blog mes ble struct 一半 har void

【BZOJ2342】雙倍回文(回文樹)

題面

BZOJ

題解

構建出回文樹之後
\(fail\)樹上進行\(dp\)
如果一個點代表的回文串長度為\(4\)的倍數
並且存在長度為它的一半的回文後綴
那麽就是可行的
如何維護長度是一半的回文後綴?
\(fail\)樹上的父親一定包括了它的所有的回文後綴
因此在\(fail\)樹上\(dfs\),同時記錄一下每個長度的回文出現的次數
這樣訪問到一個節點就可以直接檢查了

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath> #include<algorithm> #include<set> #include<map> #include<vector> #include<queue> using namespace std; #define ll long long #define RG register #define MAX 520000 inline int read() { RG int x=0,t=1;RG char ch=getchar(); while((ch<'0'||ch>'9'
)&&ch!='-')ch=getchar(); if(ch=='-')t=-1,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return x*t; } int n,ans; char ch[MAX]; struct Line{int v,next;}e[MAX]; int h[MAX],cnt=1; inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;} struct
Palindromic_Tree { struct Node { int son[26]; int ff,len; }t[MAX]; int tot,last; void init() { t[tot=1].len=-1; t[0].ff=t[1].ff=1; } void extend(int c,int n,char *s) { int p=last; while(s[n-t[p].len-1]!=s[n])p=t[p].ff; if(!t[p].son[c]) { int v=++tot,k=t[p].ff; t[v].len=t[p].len+2; while(s[n-t[k].len-1]!=s[n])k=t[k].ff; t[v].ff=t[k].son[c]; t[p].son[c]=v; Add(t[v].ff,v); } last=t[p].son[c]; } int vis[MAX]; void dfs(int u) { if(t[u].len%4==0&&vis[t[u].len/2])ans=max(ans,t[u].len); ++vis[t[u].len]; for(int i=h[u];i;i=e[i].next)dfs(e[i].v); --vis[t[u].len]; } }PT; int main() { PT.init(); n=read(); scanf("%s",ch+1); Add(1,0); for(int i=1;i<=n;++i)PT.extend(ch[i]-97,i,ch); PT.dfs(1); printf("%d\n",ans); return 0; }

【BZOJ2342】雙倍回文(回文樹)