[접미사 로봇 DP] LOJ#6071.'2017 산동 1차 훈련Day5'문자열

5099 단어 DP접미사 로봇
fi, j는 전 i개의 문자열을 표시하고 j로 끝나는 받아들일 수 있는 문자열의 개수를 나타낸다.
그러면 DP의 이동은 접미사 자동기로 할 수 있어요.
#include 
#include 
#include 
#include 

using namespace std;

const int N=4000010,P=1e9+7;

int n,cnt=1,len;
int nxt[N][30],fail[N],f[30],stp[N],t[N],r[N],g[N],p=1;
char a[N];

inline void extend(int x){
    int np=++cnt; stp[np]=stp[p]+1;
    while(p && !nxt[p][x]) nxt[p][x]=np,p=fail[p];
    if(!p) fail[np]=1;
    else{
        int q=nxt[p][x];
        if(stp[q]==stp[p]+1) fail[np]=q;
        else{
            int nq=++cnt; stp[nq]=stp[p]+1;
            memcpy(nxt[nq],nxt[q],sizeof(nxt[nq]));
            fail[nq]=fail[q];
            fail[q]=fail[np]=nq;
            while(p && nxt[p][x]==q) nxt[p][x]=nq,p=fail[p];
        }
    }
    p=np;
}

int main(){
    scanf("%d",&n);
    while(n--){
        scanf("%s",a+1); len=strlen(a+1);
        for(int i=len;i;i--) extend(a[i]-'a');
        for(int i=0;i<=cnt;i++) t[i]=0;
        for(int i=1;i<=cnt;i++) t[stp[i]]++;
        for(int i=1;i<=cnt;i++) t[i]+=t[i-1];
        for(int i=1;i<=cnt;i++) r[t[stp[i]]--]=i;
        for(int i=cnt;i;i--){
            int x=r[i]; g[x]=1;
            for(int j=0;j<26;j++)
                if(nxt[x][j]) (g[x]+=g[nxt[x][j]])%=P;
                else (g[x]+=f[j])%=P;
        }
        for(int i=0;i<26;i++)
            if(nxt[1][i]) f[i]=g[nxt[1][i]];
        for(int i=1;i<=cnt;i++){
            stp[i]=fail[i]=0;
            for(int j=0;j<26;j++) nxt[i][j]=0;
        }
        cnt=p=1;
    }
    int ans=0;
    for(int i=0;i<26;i++) (ans+=f[i])%=P;
    printf("%d
"
,ans+1); }

좋은 웹페이지 즐겨찾기