JSOI 2007 文本生成器 【AC自动机,树形DP】

JSOI 2007 文本生成器

 

题目见链接。

 

题解:

建立在 AC自动机 上的 树形DP。

先把单词建立 trie 树,并标记是否为一个单词的结尾(bool : ed), 预处理 fail 指针, ed |= fail.ed

然后求 可读,可以用 总的 减去 不可读的

设 f[i][j] 表示 到了第 i 位,第 i 位上的节点编号为 j 的方案数,则

f[i][son[j]] = (f[i-1][j] + f[i][son[j]] ) % mo 。

最后用 ans - f[m][i] ( i 节点不为单词末尾)

 

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=6005,M=105,mo=10007;
 4 char s[N];
 5 int rt,tot,q[N],head,tail,ans1=1,ans2,f[M][N],n,m;
 6 struct node{
 7     int fail,nxt[26];
 8     bool ed;
 9 }e[N];
10 inline void insert(char *s)
11 {
12     rt=0;
13     for (int i=0; s[i]; ++i)
14     {
15         if (!e[rt].nxt[s[i]-'A'])
16           e[rt].nxt[s[i]-'A']=++tot;
17         rt=e[rt].nxt[s[i]-'A'];
18     }
19     e[rt].ed=1;
20 }
21 inline void getfail()
22 {
23     rt=0; head=tail=0;
24     for (int i=0; i<26; ++i)
25       if (e[rt].nxt[i]) q[++tail]=e[rt].nxt[i];
26     while (head<tail)
27     {
28         int x=q[++head];
29         for (int i=0; i<26; ++i)
30           if (e[x].nxt[i])
31           {
32                 e[e[x].nxt[i]].fail=e[e[x].fail].nxt[i];
33                 q[++tail]=e[x].nxt[i];
34           }
35           else e[x].nxt[i]=e[e[x].fail].nxt[i];
36         e[x].ed|=e[e[x].fail].ed;
37     }
38 }
39 inline void doing()
40 {
41     f[0][0]=1;
42     for (int i=1; i<=m; ++i)
43       for (int j=0; j<=tot; ++j)
44       {
45           if (e[j].ed) continue;
46           for (int k=0; k<26; ++k)
47             f[i][e[j].nxt[k]]=(f[i][e[j].nxt[k]]+f[i-1][j])%mo;
48       }
49     for (int i=0; i<=tot; ++i)
50       if (!e[i].ed) ans2+=f[m][i];
51     for (int i=1; i<=m; ++i)
52       ans1=(ans1*26)%mo;
53     printf("%d\n",((ans1-ans2)%mo+mo)%mo);
54 }
55 int main()
56 {
57     scanf("%d%d",&n,&m);
58     for (int i=1; i<=n; ++i)
59       scanf("%s",s),insert(s);
60     getfail();
61     doing();
62     return 0;
63 }
View Code

 

 

 

 

 

 

fighting fighting fighting!!!

 

posted on 2018-09-20 21:07  Frank-King  阅读(187)  评论(0编辑  收藏  举报