[后缀自动机 DP] LOJ#6071. 「2017 山东一轮集训 Day5」字符串

来源:互联网 发布:电脑电话软件 编辑:程序博客网 时间:2024/05/19 23:53

fi,j 表示前 i 个串,以 j 结尾的可接受的字符串的个数。

那么DP的转移可以用后缀自动机转移

#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>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\n",ans+1);}
阅读全文
0 0
原创粉丝点击