bzoj 3676: [Apio2014]回文串 manachar+后缀自动机+倍增(回文树)
2017-04-09 20:47
519 查看
题意
考虑一个只包含小写字母的字符串s。我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度。请你求出s的所有回文子串中的最大出现值。n<=300000
分析
因为自己对马拉车的性质不太熟悉,所以一开始没做出来。考虑在跑马拉车算法的时候,所有本质不同的回文串必然包含在所有能使mx增加的回文串内,也就是最多只有O(n)个。那么我们只要求出后缀自动机,然后每找到一个回文串就扔进后缀自动机里跑一下就好了。
但是由于找祖先太慢,我们可以先预处理,然后倍增找即可。
后来才发现这是回文树的裸题。然后就去学习了一发。回文树介绍
代码
后缀自动机#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; const int N=300005; const int M=N*2; int n,pos ,mx[M],c[M],b ,f[M],fa[M][19],ch[M][26],last,cnt,l[N*2]; char a[N*2],s ; LL ans; void ins(int x,int id) { int p,q,np,nq; p=last;last=np=++cnt;mx[np]=mx[p]+1;f[np]=1;pos[id]=np; for (;!ch[p][x]&&p;p=fa[p][0]) ch[p][x]=np; if (!p) fa[np][0]=1; else { q=ch[p][x]; if (mx[q]==mx[p]+1) fa[np][0]=q; else { nq=++cnt;mx[nq]=mx[p]+1; memcpy(ch[nq],ch[q],sizeof(ch[q])); fa[nq][0]=fa[q][0]; fa[q][0]=fa[np][0]=nq; for (;ch[p][x]==q;p=fa[p][0]) ch[p][x]=nq; } } } void prework() { for (int i=1;i<=cnt;i++) b[mx[i]]++; for (int i=1;i<=n;i++) b[i]+=b[i-1]; for (int i=1;i<=cnt;i++) c[b[mx[i]]--]=i; for (int i=cnt;i>=1;i--) f[fa[c[i]][0]]+=f[c[i]]; for (int i=1;i<=cnt;i++) for (int j=1;j<=18;j++) fa[c[i]][j]=fa[fa[c[i]][j-1]][j-1]; } void query(int l,int r) { if (a[l]=='#') return; l/=2;r/=2; int now=pos[r]; for (int i=18;i>=0;i--) if (mx[fa[now][i]]>=r-l+1) now=fa[now][i]; ans=max(ans,(LL)(r-l+1)*f[now]); } void manachar() { for (int i=1;i<=n*2+1;i++) if (i%2==1) a[i]='#'; else a[i]=s[i/2]; int mx=0,id; for (int i=1;i<=n*2+1;i++) { if (i<=mx) l[i]=min(mx-i+1,l[id*2-i]); while (i+l[i]<=n*2+1&&i+l[i]>=1&&a[i+l[i]]==a[i-l[i]]) { l[i]++; if (i+l[i]-1>mx) mx=i+l[i]-1,id=i,query(i-l[i]+1,i+l[i]-1); } } } int main() { scanf("%s",s+1); n=strlen(s+1); cnt=last=1; for (int i=1;i<=n;i++) ins(s[i]-'a',i); prework(); manachar(); printf("%lld",ans); return 0; }
回文树
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; typedef long long LL; const int N=300005; int n; char s ; struct pam { int ch [26],size ,fail ,len ,last,sz; pam() { len[1]=-1;fail[0]=fail[1]=1;sz=1; } void ins(int c,int n) { int p=last; while (s[n-1-len[p]]!=s ) p=fail[p]; if (!ch[p][c]) { int now=++sz,k=fail[p];len[now]=len[p]+2; while (s[n-1-len[k]]!=s ) k=fail[k]; fail[now]=ch[k][c];ch[p][c]=now; } last=ch[p][c];size[last]++; } void solve() { LL ans=0; for (int i=sz;i>=1;i--) size[fail[i]]+=size[i],ans=max(ans,(LL)size[i]*len[i]); printf("%lld",ans); } }pam; int main() { scanf("%s",s+1); n=strlen(s+1); for (int i=1;i<=n;i++) pam.ins(s[i]-'a',i); pam.solve(); return 0; }
相关文章推荐
- [manacher 后缀自动机 || 回文自动机] BZOJ 3676 [Apio2014]回文串
- [bzoj3676][Apio2014]回文串——Manacher+后缀自动机+倍增
- [Bzoj3676][Apio2014]回文串(后缀自动机)(parent树)(倍增)
- [bzoj3676][Apio2014]回文串 回文自动机(回文树)
- 【BZOJ3676】[Apio2014]回文串 回文自动机
- [回文自动机] BZOJ3676 [Apio2014] . 回文串
- [BZOJ]3676 [APIO2014] 回文串 回文自动机
- BZOJ 3676 [Apio2014]回文串 回文自动机
- 【bzoj3676】[Apio2014]回文串 后缀自动机
- [BZOJ3676][Apio2014]回文串(回文自动机)
- BZOJ3676 APIO2014回文串(manacher+后缀自动机)
- bzoj 3676: [Apio2014]回文串 (回文自动机)
- bzoj 3676: [Apio2014]回文串 回文自动机
- 【bzoj3676】[Apio2014]回文串 —— 回文自动机的学习
- bzoj 3676: [Apio2014]回文串 -- 回文自动机
- 【bzoj3676】[Apio2014]回文串 回文自动机
- bzoj3676 [Apio2014]回文串(回文自动机)
- 回文自动机 模板 bzoj3676【Apio2014】回文串
- 【回文自动机】bzoj3676 [Apio2014]回文串
- [回文自动机] BZOJ 3676: [Apio2014]回文串