bzoj1030 文本生成器 Trie图+dp

---恢复内容开始---

套路题

dp[i][j]表示文本第i个字符匹配到trie图的第j个节点且没有出现过完整单词的方案数

拿26^n-dp[n]就好

 

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#define mod 10007
using namespace std;
int n,m,tot,ans=1;
char s[105];
bool ed[6005];
int dp[105][6005];
struct node{
    int son[26];
    int fail;
}tr[6005];
void build(char b[]){
    int now=0,len=strlen(b+1);
    for(int i=1;i<=len;i++){
        int k=b[i]-'A';
        if(!tr[now].son[k])tr[now].son[k]=++tot;
        now=tr[now].son[k];
    }
    ed[now]=true;
}
void getfail(){
    queue<int>que;
    for(int i=0;i<26;i++){
        if(tr[0].son[i]){
            que.push(tr[0].son[i]);
        }
    }
    while(!que.empty()){
        int u=que.front();
        que.pop();
        for(int i=0;i<26;i++){
            if(!tr[u].son[i]){
                tr[u].son[i]=tr[tr[u].fail].son[i];
                continue;
            }
            tr[tr[u].son[i]].fail=tr[tr[u].fail].son[i];
            ed[tr[u].son[i]]|=ed[tr[tr[u].fail].son[i]];
            que.push(tr[u].son[i]);
        }
    }
}
void DP(){
    dp[0][0]=1;
    for(int i=1;i<=m;i++){
        for(int j=0;j<=tot;j++){
            for(int k=0;k<26;k++){
                if(!ed[tr[j].son[k]]){
                    (dp[i][tr[j].son[k]]+=dp[i-1][j])%=mod;
                }
            }
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%s",s+1);
        build(s);
    }
    getfail();DP();
    for(int i=1;i<=m;i++){
        ans*=26;
        ans%=mod;
    }
    for(int i=0;i<=tot;i++){
        ans=((ans-dp[m][i])%mod+mod)%mod;
    }
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2018-09-27 23:23  Mr_Handsome  阅读(98)  评论(0编辑  收藏