HIHOcoder 1445 后缀自动机二·重复旋律5

思路

题目要求求出有多少个不同的子串出现

因为后缀自动机每个状态存储的是连续的后缀,所以一个状态对应的子串个数就是maxlen[x]-minlen[x]+1

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
const int MAXN = 1000100*2;
int maxlen[MAXN],minlen[MAXN],trans[MAXN][26],suflink[MAXN],cnt=0,n=0;
char s[MAXN];
int new_st(int _maxlen,int _minlen,int *_trans,int _suflink){
    ++cnt;
    maxlen[cnt]=_maxlen;
    minlen[cnt]=_minlen;
    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_st(maxlen[u]+1,0,NULL,0);
    while(u&&(!trans[u][c])){
        trans[u][c]=z;
        u=suflink[u];
    }
    if(u==0){
        suflink[z]=1;
        minlen[z]=1;
        return z;
    }
    int v=trans[u][c];
    if(maxlen[u]+1==maxlen[v]){
        suflink[z]=v;
        minlen[z]=maxlen[v]+1;
        return z;
    }
    int y=new_st(maxlen[u]+1,0,trans[v],suflink[v]);
    suflink[v]=suflink[z]=y;
    minlen[v]=minlen[z]=maxlen[y]+1;
    while(u&&trans[u][c]==v){
        trans[u][c]=y;
        u=suflink[u];
    }
    minlen[y]=maxlen[suflink[y]]+1;
    return z;
}
int main(){
    scanf("%s",s+1);
    n=strlen(s+1);
    int pre=1;
    cnt=1;
    long long ans=0;
    for(int i=1;i<=n;i++)
        pre=add_len(pre,s[i]-'a');
    for(int i=2;i<=cnt;i++){
        ans+=maxlen[i]-minlen[i]+1;
        // printf("%d %d %d %d
",i,suflink[i],minlen[i],maxlen[i]);
    }
    printf("%lld
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/dreagonm/p/10468727.html