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

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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值