BZOJ 1030 [JSOI2007]文本生成器 (Trie图+DP)

题目大意:给你一堆字符串,一个串不合法的条件是这些字符串中任意一个是这个串的子串,求合法的串的数量

其实这道题比 [HNOI2008]GT考试 那道题好写一些,但道理是一样的

只不过这道题的答案可以转化为 所有可能的字符串(26^m)数量 - 不合法的字符串数量

定义f[i][j]表示匹配到了第i个字符,现在在Trie树上匹配到了第j个节点的方案数

GT考试是跳Next,每次找出 和 插入这个字符后形成的字符串 具有相同最长后缀的位置

那么对于Trie图来说,这不就是fail指针么

Trie树被补全成Trie树后

如果在原来的Trie树中某个节点x,它并没有儿子ch[x][c],那么在补全后,ch[x][c]自动指向的是x的fail指针指向的c儿子,即ch[fail[x]][c]

这不正是我们想要转移的位置么,非常智能

总结:字符串套KMP/AC自动机/Trie图的题,通常都有f[i][j]表示文本串匹配到了第i位,模式串匹配到了第j位这类状态,且有一些题可以用矩阵乘法优化。 

 1 #include <queue>
 2 #include <cmath>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <algorithm>
 6 #define ll long long 
 7 #define N 6010
 8 #define M 28
 9 #define mod 10007
10 #define ui unsigned int
11 #define idx(x) (x-'A'+1)
12 #define inf 0x3f3f3f3f
13 using namespace std;
14 //re
15 int n,m;
16 char str[65][110];
17 int f[120][N];
18 int qpow(int x,int y){
19     int ans=1;
20     while(y){
21         if(y&1) ans=(ans*x)%mod;
22         x=(x*x)%mod,y>>=1;
23     }return ans;
24 }
25 struct Trie{
26     int ch[N][M],fa[N],fail[N],ed[N],tot;
27     void Build()
28     {
29         for(int i=1;i<=n;i++)
30         {
31             int len=strlen(str[i]+1),x=0;
32             for(int j=1;j<=len;j++)
33             {
34                 int c=idx(str[i][j]);
35                 if(!ch[x][c])
36                     tot++,ch[x][c]=tot,fa[tot]=x;
37                 x=ch[x][c];
38                 if(j==len) ed[x]=1;
39             }
40         }
41     }
42     void Fail()
43     {
44         queue<int>q;
45         for(int i=1;i<=26;i++)
46             if(ch[0][i]) q.push(ch[0][i]);
47         while(!q.empty())
48         {
49             int x=q.front();q.pop();
50             for(int i=1;i<=26;i++)
51                 if(ch[x][i])
52                     fail[ch[x][i]]=ch[fail[x]][i],
53                     q.push(ch[x][i]);
54                 else 
55                     ch[x][i]=ch[fail[x]][i];
56         } 
57     }
58     int solve()
59     {
60         f[0][0]=1;
61         queue<int>q;
62         for(int i=0;i<=m;i++)
63             for(int x=0;x<=tot;x++)
64                 for(int c=1;c<=26;c++)
65                 {
66                     int flag=1;
67                     for(int k=ch[x][c];k;k=fail[k])
68                         if(ed[k]){flag=0;break;}
69                     if(!flag) continue;
70                     (f[i+1][ch[x][c]]+=f[i][x])%=mod;
71                 }
72         int ans=0;     
73         for(int x=0;x<=tot;x++)
74             if(!ed[x]) (ans+=f[m][x])%=mod;
75         return ans;
76     }
77 }t;
78 int main()
79 {
80     scanf("%d%d",&n,&m);
81     for(int i=1;i<=n;i++) scanf("%s",str[i]+1);
82     t.Build();
83     t.Fail();
84     printf("%u\n",(qpow(26,m)-t.solve()+mod)%mod);
85     return 0;
86 }

 

posted @ 2018-09-24 22:47  guapisolo  阅读(108)  评论(0编辑  收藏