SAM 后缀自动机
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SAM 后缀自动机相关的知识,希望对你有一定的参考价值。
bzoj3676 回文串
题目大意:给定一个字符串,求其中某种回文串的长度*出现次数的最大值。
思路:建立后缀自动机,用manachur求出本质不同的回文串(也就是比较使pp[i]+1的时候),然后在后缀自动机上的相应节点网上找fa,统计siz。
(这道题目中manachur不能加字符(会mle),所以要奇偶分别匹配,但是偶数的时候是有问题的。)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define N 600005 #define maxsiz 26 #define up 20 #define LL long long using namespace std; char ss[N]; int sz,last,ll,pp[N]={0}; LL ans=0LL; struct use{ int ch[N][maxsiz],fa[N],mx[N],siz[N],que[N],id[N],anc[N][up]; int idx(char ch){return ch-‘a‘;} void extend(char x,int ii){ int i,j,u,p,q,np,nq; u=idx(x);p=last;id[ii]=np=++sz; mx[np]=mx[p]+1;siz[np]=1; while(p && !ch[p][u]){ch[p][u]=np;p=fa[p];} if (!p) fa[np]=1; else{ q=ch[p][u]; if (mx[p]+1==mx[q]) fa[np]=q; else{ nq=++sz;mx[nq]=mx[p]+1; memcpy(ch[nq],ch[q],sizeof(ch[q])); fa[nq]=fa[q];fa[q]=fa[np]=nq; while(ch[p][u]==q){ch[p][u]=nq;p=fa[p];} } }last=np;} void pre(){ int i,j; memset(pp,0,sizeof(pp)); for (i=1;i<=sz;++i) ++pp[mx[i]]; for (i=1;i<=ll;++i) pp[i]+=pp[i-1]; for (i=sz;i;--i) que[pp[mx[i]]--]=i; for (i=sz;i;--i) siz[fa[que[i]]]+=siz[que[i]]; memset(anc[0],0,sizeof(anc[0])); for (i=1;i<=sz;++i){ anc[que[i]][0]=fa[que[i]]; for (j=1;j<up;++j) anc[que[i]][j]=anc[anc[que[i]][j-1]][j-1]; }} void query(int l,int r){ int u,v,i,j;u=id[r]; for (i=up-1;i>=0;--i) if (mx[anc[u][i]]>=r-l+1) u=anc[u][i]; ans=max(ans,(LL)siz[u]*(LL)(r-l+1)); } }sam; void work(){ int i,j,mx,id; memset(pp,0,sizeof(pp)); for (mx=0,i=1;i<ll;++i){ if (mx>i) pp[i]=min(pp[2*id-i],mx-i); else{pp[i]=1;sam.query(i,i);} for (;ss[i-pp[i]]==ss[i+pp[i]];++pp[i]) sam.query(i-pp[i],i+pp[i]); if (pp[i]+i>mx){mx=pp[i]+i;id=i;} }memset(pp,0,sizeof(pp)); for (mx=0,i=1;i<ll;++i){ if (mx>i) pp[i]=min(pp[2*id-i-1],mx-i); else pp[i]=0; for (;ss[i-pp[i]]==ss[i+pp[i]+1];++pp[i]) sam.query(i-pp[i],i+pp[i]+1); if (pp[i]+i>mx){mx=pp[i]+i;id=i;} } } int main(){ int i,j,n; scanf("%s",ss+1);ss[0]=‘&‘; ll=strlen(ss+1);ss[++ll]=‘#‘; for (sz=last=1,i=1;i<ll;++i) sam.extend(ss[i],i); sam.pre();work();printf("%I64d ",ans); }
以上是关于SAM 后缀自动机的主要内容,如果未能解决你的问题,请参考以下文章