bzoj 1030 文本生成器

题目大意:

生成一个长度为n的字符串,使它包含给出串中的一个

求这个生成串的方案数

思路:

dp i j表示匹配到i位,trie树上第j个节点的方案数

可以得到dp方程,dp i j 可以转移到 dp i+1 ch[j] 

记录一下结尾处的节点

然后用总方案数-所有匹配不到的

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstdlib>
 5 #include<cstring>
 6 #include<algorithm>
 7 #include<vector>
 8 #include<queue>
 9 #define inf 2139062143
10 #define ll long long
11 #define MAXN 6010
12 #define MOD 10007
13 using namespace std;
14 inline int read()
15 {
16     int x=0,f=1;char ch=getchar();
17     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
18     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
19     return x*f;
20 }
21 int n,dp[110][MAXN],m,tot,sz,ans;
22 char s[110];
23 bool ed[MAXN];
24 struct Trie {int fail,ch[26];}tr[MAXN];
25 void insert(char *c,int len)
26 {
27     int pos=0;
28     for(int i=1;i<=len;i++)
29     {
30         if(!tr[pos].ch[c[i]-'A']) tr[pos].ch[c[i]-'A']=++sz;
31         pos=tr[pos].ch[c[i]-'A'];
32     }
33     ed[pos]=1;
34 }
35 void build()
36 {
37     queue <int> q;
38     for(int i=0;i<26;i++) if(tr[0].ch[i]) q.push(tr[0].ch[i]);
39     while(!q.empty())
40     {
41         int k=q.front();q.pop();
42         for(int i=0;i<26;i++)
43             if(tr[k].ch[i]) tr[tr[k].ch[i]].fail=tr[tr[k].fail].ch[i],q.push(tr[k].ch[i]);
44             else tr[k].ch[i]=tr[tr[k].fail].ch[i];
45         ed[k]+=ed[tr[k].fail];
46     }
47 }
48 int main()
49 {
50     n=read(),m=read();
51     for(int i=1;i<=n;i++) scanf("%s",s+1),insert(s,strlen(s+1));
52     build();
53     dp[0][0]=tot=1;
54     for(int i=1;i<=m;i++) (tot*=26)%=MOD;
55     for(int i=1;i<=m;i++)
56         for(int j=0;j<=sz;j++)
57         {
58             if(ed[j]) continue;
59             for(int k=0;k<26;k++) (dp[i][tr[j].ch[k]]+=dp[i-1][j])%=MOD;
60         }
61     for(int i=0;i<=sz;i++) if(!ed[i]) (ans+=dp[m][i])%=MOD;
62     printf("%d",(tot-ans+MOD)%MOD);
63 }
View Code

 orz没写主函数里忘了写build调了一年

posted @ 2018-01-09 17:25  jack_yyc  阅读(156)  评论(0编辑  收藏  举报