双倍快乐(回文树)
这一天Zweib突发奇想,如果用有一个字符串 t是由2个非空的回文串 x 和 y 组成的(,>0),不就可以获得双倍的快乐了吗(迫真突发奇想),于是他想从一个给定的字符串 s 中找出一个子串 t 满足 t 由2个回文串组成,但是他不知道自己能取到的 t 最长为多少,你能帮帮他吗?
题解:
#include<bits/stdc++.h> using namespace std; typedef unsigned long long ll; const int maxn=3e5+100; int a[maxn]; ll f[maxn]; ll p[maxn]; ll cal (int l,int r) { if (l==0) return f[r]; return f[r]-f[l-1]*p[r-l+1]; } bool check (int l,int r) { int mid=(l+r)>>1; if ((r-l+1)&1) return cal(l,mid)==cal(mid,r); else return cal(l,mid)==cal(mid+1,r); //分别判断 } int Hash[maxn];//表示起点为i的回文串的最大长度 struct palin_Tree { //回文树 int nxt[maxn][26]; int fail[maxn]; int len[maxn]; int cnt[maxn]; int S[maxn]; int ind[maxn]; int last,id,n; /* * 一个节点表示一个本质不同的回文串 * len[i]表示回文串i的长度 * nxt[i][c]表示编号为i的节点表示的回文串在两边添加字符c以后变成的回文串的编号 * cnt[i]表示节点i表示的本质不同的串的个数 * fail[i]表示节点i失配以后跳转不等于自身的节点i表示的回文串的最长后缀回文串 * last表示新添加一个字母后形成的最长回文串表示的节点 * S[i]表示第i次添加的字符 * ind[i]表示第i号节点是插入到第ind[i]号字符串产生的节点 */ int newNode (int x) { for (int i=0;i<26;i++) nxt[id][i]=0; cnt[id]=0; len[id]=x; return id++; } void init () { id=0; newNode(0); newNode(-1); fail[0]=1; S[0]=-1; last=n=0; } int getfail (int x) { while (S[n-len[x]-1]!=S[n]) x=fail[x]; return x; } void insert (int c) { c-='a'; S[++n]=c; int cur=getfail(last); if (!nxt[cur][c]) { int u=newNode(len[cur]+2); fail[u]=nxt[getfail(fail[cur])][c]; nxt[cur][c]=u; } last=nxt[cur][c]; cnt[last]++; ind[last]=n; } int getMax () { int Max=0; for (int i=id-1;i>=0;i--) cnt[fail[i]]+=cnt[i]; for (int i=0;i<id;i++) //if (check(ind[i]-len[i],ind[i]-1)) // a[len[i]]+=cnt[i] Hash[ind[i]-len[i]]=max(Hash[ind[i]-len[i]],len[i]); for (int i=id-1;i>=0;i--) if (len[i]>=0&&Hash[ind[i]]) Max=max(Max,len[i]+Hash[ind[i]]); return Max; } }Palin_Tree; char s[maxn]; int main () { p[0]=1; for (int i=1;i<maxn;i++) p[i]=p[i-1]*13331; while (~scanf("%s",s)) { int ans=0; memset(Hash,0,sizeof(Hash)); int len=strlen(s); for (int i=0;i<=len;i++) a[i]=0; Palin_Tree.init(); for (int i=0;i<len;i++) Palin_Tree.insert(s[i]); f[0]=s[0]; for (int i=1;i<len;i++) f[i]=f[i-1]*13331+s[i]; ans=max(ans,Palin_Tree.getMax()); memset(Hash,0,sizeof(Hash)); len=strlen(s); for (int i=0;i<=len;i++) a[i]=0; Palin_Tree.init(); for (int i=len-1;i>=0;i--) Palin_Tree.insert(s[i]); f[0]=s[0]; for (int i=1;i<len;i++) f[i]=f[i-1]*13331+s[i]; ans=max(ans,Palin_Tree.getMax()); cout<<ans<<"\n"; } }