字符串-后缀自动机

学了好久啊。

基本定义看洛谷日报就好啦。

大概就是走DAG的边相当于添加字符,跳parent树的边相当于删除一段前缀。这样就好理解了。

如果想要得到后缀树,考虑对反串建后缀自动机然后记录endpos(或称right)集中的一个元素,就得到了parent树上边的信息。其实没什么用,万一题目要求输出字符串呢。

板子也自己去看叭

算了还是放一份板子吧

 

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+6;
const int Z=128-' ';

int f[N<<1],c[N<<1][Z],l[N<<1];
int tb[N<<1],ep[N<<1];
int pr=1,cnt=1;

void ins(int x){
    int p=pr,v=pr=++cnt;
    l[v]=l[p]+1;
    ep[v]=tb[v]=l[v];
    for(;p&&!c[p][x];p=f[p])c[p][x]=v;
    if(!p)f[v]=1;
    else{
        int u=c[p][x];
        if(l[u]==l[p]+1)f[v]=u;
        else{
            int w=++cnt;
            f[w]=f[u];
            ep[w]=ep[u];
            for(int i=0;i<Z;i++)c[w][i]=c[u][i];
            l[w]=l[p]+1;
            f[u]=f[v]=w;
            for(;p&&c[p][x]==u;p=f[p])c[p][x]=w;
        }
    }
}

vector<int>e[N<<1];
int t[N][Z];

void dfs(int v){
    for(int i=0;i<e[v].size();i++){
        dfs(e[v][i]);
        ep[v]=ep[e[v][i]];
    }
}

void dfs2(int v){
    if(tb[v])printf("%d ",tb[v]);
    for(int i=0;i<Z;i++)
        if(t[v][i])dfs2(t[v][i]);
}

char s[N];

int main()
{
    scanf("%s",s+1);
    int n=strlen(s+1),i;
    for(i=n;i;i--)
        ins(s[i]-' ');
    for(i=2;i<=cnt;i++)
        if(tb[i])tb[i]=n+1-tb[i];
    for(i=2;i<=cnt;i++)
        e[f[i]].push_back(i);
    dfs(1);
    for(i=2;i<=cnt;i++)
        t[f[i]][s[n+1-(ep[i]-l[f[i]])]-' ']=i;
    dfs2(1);
    return 0;
}

 

这是SA板子题,会MLE几个点。

SAM板子题当然要用SA来写啦

#include<bits/stdc++.h>
using namespace std;
typedef long long i64;
const int N=1e6+6;

char s[N];
int t1[N],t2[N],c[N];
int sa[N],rk[N],ht[N];

void gtsa(int n,int m){
    int *x=t1,*y=t2,i,j,p=0;
    for(i=1;i<=n;i++)++c[x[i]=s[i]];
    for(i=1;i<=m;i++)c[i]+=c[i-1];
    for(i=n;i;i--)sa[c[x[i]]--]=i;
    for(j=1;j<=n&&p<n;j<<=1){
        p=0;
        for(i=n-j+1;i<=n;i++)y[++p]=i;
        for(i=1;i<=n;i++)if(sa[i]>j)y[++p]=sa[i]-j;
        for(i=1;i<=m;i++)c[i]=0;
        for(i=1;i<=n;i++)++c[x[y[i]]];
        for(i=1;i<=m;i++)c[i]+=c[i-1];
        for(i=n;i;i--)sa[c[x[y[i]]]--]=y[i];
        swap(x,y);
        p=1;x[sa[1]]=1;
        for(i=2;i<=n;i++)
            x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j]?p:++p;
        m=p;
    }
    for(i=1;i<=n;i++)rk[sa[i]]=i;
    p=1;
    for(i=1;i<=n;i++){
        j=sa[rk[i]-1];
        if(p)--p;
        while(s[i+p]==s[j+p])++p;
        ht[rk[i]]=p;
    }
}

int b[N],h[N],tp;

int main()
{
    scanf("%s",s+1);
    int n=strlen(s+1);
    gtsa(n,127);
    tp=0;
    i64 ans=0;
    int i,nb;
    for(i=1;i<=n;i++){
        nb=i;
        while(h[tp]>ht[i+1])ans=max(ans,1ll*(i-b[tp]+1)*h[tp]),nb=b[tp],--tp;
        ++tp;b[tp]=nb;h[tp]=ht[i+1];
    }
    printf("%lld",ans);
    return 0;
}

 

posted @ 2019-07-26 11:30  花舞月朦胧  阅读(204)  评论(0)    收藏  举报