[JSOI2007]文本生成器

题目大意:
  给定$n(n\le60)$个字符串$s_i(|s_i|\le100)$,问有多少个长度为$m(m\le100)$的字符串$t$满足至少包含一个$s_i$?保证所有字符串均由大写英文字母构成。

思路:
  建立AC自动机。用$f[i][j]$表示构造到$t$的第$i$位,对应自动机上编号为$j$的结点,不包含任何$s_i$的方案数。显然遇到危险结点需要跳过,否则直接转移即可。答案即为$26^m-\sum f[m][i]$。

 1 #include<queue>
 2 #include<cstdio>
 3 #include<cctype>
 4 inline int getint() {
 5     register char ch;
 6     while(!isdigit(ch=getchar()));
 7     register int x=ch^'0';
 8     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
 9     return x;
10 }
11 const int N=60,L=101,S=26,mod=10007;
12 char s[L];
13 int f[L][N*L];
14 class AhoCorasick {
15     private:
16         bool val[N*L];
17         std::queue<int> q;
18         int ch[N*L][S],fail[N*L];
19         int sz,new_node() {
20             return ++sz;
21         }
22         int idx(const int &c) const {
23             return c-'A';
24         }
25     public:
26         void insert(const char s[]) {
27             int p=0;
28             for(register int i=0;s[i];i++) {
29                 const int c=idx(s[i]);
30                 p=ch[p][c]?:ch[p][c]=new_node();
31             }
32             val[p]=true;
33         }
34         void get_fail() {
35             for(register int c=0;c<S;c++) {
36                 if(ch[0][c]) q.push(ch[0][c]);
37             }
38             while(!q.empty()) {
39                 const int &x=q.front();
40                 for(register int c=0;c<S;c++) {
41                     int &y=ch[x][c];
42                     if(!y) {
43                         y=ch[fail[x]][c];
44                         continue;
45                     }
46                     fail[y]=ch[fail[x]][c];
47                     val[y]|=val[fail[y]];
48                     q.push(y);
49                 }
50                 q.pop();
51             }
52         }
53         int solve(const int &n,const int &m) const {
54             int ret=f[0][0]=1;
55             for(register int i=1;i<=m;i++) {
56                 (ret*=S)%=mod;
57                 for(register int j=0;j<=sz;j++) {
58                     if(!f[i-1][j]) continue;
59                     for(register int c=0;c<S;c++) {
60                         if(!val[ch[j][c]]) (f[i][ch[j][c]]+=f[i-1][j])%=mod;
61                     }
62                 }
63             }
64             for(register int i=0;i<=sz;i++) {
65                 ret=(ret-f[m][i]+mod)%mod;
66             }
67             return ret;
68         }
69 };
70 AhoCorasick ac;
71 int main() {
72     const int n=getint(),m=getint();
73     for(register int i=0;i<n;i++) {
74         scanf("%s",s);
75         ac.insert(s);
76     }
77     ac.get_fail();
78     printf("%d\n",ac.solve(n,m));
79     return 0;
80 }

 

posted @ 2018-03-15 16:09  skylee03  阅读(90)  评论(0编辑  收藏  举报