P4555 [国家集训队]最长双回文串
题目大意
求S的最长双回文子串T,即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y都是回文串
建两个回文自动机,一个维护前缀,一个维护后缀
最后扫一遍更新答案
My complete code:
#include<cstdio> #include<string> #include<cstring> #include<iostream> using namespace std; typedef long long LL; const LL maxn=200000; struct node{ LL son[26],fail,len; }tree1[maxn],tree2[maxn]; LL last,nod1,nod2,len,ans; LL belong1[maxn],belong2[maxn]; char s1[maxn],s2[maxn]; inline void solve1(){ s1[0]='#'; tree1[0].fail=1; tree1[0].len=0; tree1[1].fail=0; tree1[1].len=-1; last=0; nod1=1; for(LL i=1;i<=len;++i){ while(s1[i-tree1[last].len-1]!=s1[i]) last=tree1[last].fail; if(!tree1[last].son[s1[i]]){ tree1[++nod1].len=tree1[last].len+2; LL j=tree1[last].fail; while(s1[i-tree1[j].len-1]!=s1[i]) j=tree1[j].fail; tree1[nod1].fail=tree1[j].son[s1[i]]; tree1[last].son[s1[i]]=nod1; } last=tree1[last].son[s1[i]]; belong1[i]=tree1[last].len; } } inline void solve2(){ s2[0]='#'; tree2[0].fail=1; tree2[0].len=0; tree2[1].fail=0; tree2[1].len=-1; last=0; nod2=1; for(LL i=1;i<=len;++i){ while(s2[i-tree2[last].len-1]!=s2[i]) last=tree2[last].fail; if(!tree2[last].son[s2[i]]){ tree2[++nod2].len=tree2[last].len+2; LL j=tree2[last].fail; while(s2[i-tree2[j].len-1]!=s2[i]) j=tree2[j].fail; tree2[nod2].fail=tree2[j].son[s2[i]]; tree2[last].son[s2[i]]=nod2; } last=tree2[last].son[s2[i]]; belong2[len-i+1]=tree2[last].len; } } int main(){ scanf(" %s",s1+1); len=strlen(s1+1); for(LL i=1;i<=len;++i){ s1[i]-='a'; s2[len-i+1]=s1[i]; } solve1(); solve2(); for(LL i=1;i<len;++i) if(belong1[i]+belong2[i+1]>ans) ans=belong1[i]+belong2[i+1]; printf("%lld",ans); return 0; }/* baacaabbacabb 12 */