P3804 【模板】后缀自动机

思路

很水的后缀自动机
找到最长的大小不为1的endpos与maxlen的乘积即可

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int MAXN = 1000100*2;
int trans[MAXN][26],suflink[MAXN],maxlen[MAXN],endpos[MAXN],ispre[MAXN],in[MAXN],n,cnt;
char s[MAXN];
int new_state(int _maxlen,int *_trans,int _suflink){
    ++cnt;
    maxlen[cnt]=_maxlen;
    if(_trans)
        for(int i=0;i<26;i++)
            trans[cnt][i]=_trans[i];
    suflink[cnt]=_suflink;
    return cnt;
}
int add_len(int u,int c){
    int z=new_state(maxlen[u]+1,NULL,0);
    ispre[z]=1;
    while(u&&(!trans[u][c])){
        trans[u][c]=z;
        u=suflink[u];
    }
    if(!u){
        suflink[z]=1;
        return z;
    }
    int v= trans[u][c];
    if(maxlen[v]==maxlen[u]+1){
        suflink[z]=v;
        return z;
    }
    int y=new_state(maxlen[u]+1,trans[v],suflink[v]);
    suflink[v]=suflink[z]=y;
    while(u&&trans[u][c]==v){
        trans[u][c]=y;
        u=suflink[u];
    }
    return z;
}
queue<int> q;
int main(){
    scanf("%s",s+1);
    n=strlen(s+1);
    int pre=1;
    cnt=1;
    for(int i=1;i<=n;i++)
        pre=add_len(pre,s[i]-'a');
    for(int i=1;i<=cnt;i++)
        in[suflink[i]]++;
    for(int i=1;i<=cnt;i++) 
        if(!in[i])
            q.push(i);
    while(!q.empty()){
        int x=q.front();
        q.pop();
        endpos[x]+=ispre[x];
        endpos[suflink[x]]+=endpos[x];
        in[suflink[x]]--;
        if(!in[suflink[x]])
            q.push(suflink[x]);
    }
    // for(int i=1;i<=cnt;i++)
    //     printf("%d %d!\n",endpos[i],maxlen[i]);
    int ans=0;
    for(int i=1;i<=cnt;i++)
        if(endpos[i]>1)
            ans=max(ans,endpos[i]*maxlen[i]);
    printf("%d\n",ans);
    return 0;   
}
posted @ 2019-03-05 08:51  dreagonm  阅读(157)  评论(0编辑  收藏  举报