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);
}
View Code

 

以上是关于SAM 后缀自动机的主要内容,如果未能解决你的问题,请参考以下文章

模板后缀自动机 (SAM)

模板后缀自动机 (SAM)

[BZOJ3676][APIO2014]回文串(Manacher+SAM)

SAM 后缀自动机

算法后缀自动机SAM

后缀自动机SAM