HDU 2825 Wireless Password

 

Wireless Password

http://acm.hdu.edu.cn/showproblem.php?pid=2825

题意:

  求有多少长度为n的串,包含给定的串的至少k个串。

分析:

  AC自动机+dp,首先对给定的m个串建立AC自动机,然后状压dp,dp[i][j][s]表示当前的串的长度是i,在AC自动机的节点j上,状态(已经满足的串)是s的方案数。

  注意:1、将每个点所满足的所有串,都或起来,这个点可以把这些子串都包含进去。2、代码40行要有,在AC自动机上一旦不匹配了,就可以走回去了。

代码:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<cmath>
 6 #include<cctype>
 7 #include<set>
 8 #include<queue>
 9 #include<vector>
10 #include<map>
11 using namespace std;
12 typedef long long LL;
13 
14 inline int read() {
15     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
16     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
17 }
18 
19 const int mod = 20090717;
20 
21 int dp[26][150][1200], ch[150][27], sta[150], q[150], fail[150], Index;
22 char s[150];
23 
24 void Insert(char *s,int id) {
25     int n = strlen(s), u = 0;
26     for (int i = 0; i < n; ++i) {
27         int c = s[i] - 'a';
28         if (!ch[u][c]) ch[u][c] = ++Index;
29         u = ch[u][c];
30     }
31     sta[u] |= (1 << id);
32 }
33 void bfs() {
34     int L = 1, R = 0;
35     for (int i = 0; i < 26; ++i) if (ch[0][i]) q[++R] = ch[0][i]; // q[++R] = i!!!
36     while (L <= R) {
37         int u = q[L ++];
38         for (int c = 0; c < 26; ++c) {
39             int v = ch[u][c];
40             if (!v) { ch[u][c] = ch[fail[u]][c]; continue; }
41             int p = fail[u]; while (p && !ch[p][c]) p = fail[p];
42             fail[v] = ch[p][c];
43             q[++R] = v;
44             sta[v] |= sta[fail[v]]; 
45         }
46     }
47 }
48 inline void add(int &x,int y) { x += y; if (x >= mod) x -= mod; }
49 inline void sub(int &x,int y) { x -= y; x < 0 && (x += mod); } 
50 void solve(int n,int m,int k) {
51     dp[0][0][0] = 1;
52     int All = (1 << m) - 1;
53     for (int i = 0; i < n; ++i) 
54         for (int j = 0; j <= Index; ++j) 
55             for (int s = 0; s <= All; ++s) {
56                 if (dp[i][j][s] <= 0) continue; 
57                 for (int c = 0; c < 26; ++c) {
58                     int nv = ch[j][c], ns = s | sta[nv];
59                     add(dp[i + 1][nv][ns], dp[i][j][s]);
60                 }
61             }
62     int ans = 0;
63     for (int s = 0; s <= All; ++s) {
64         int cnt = 0;
65         for (int i = 0; i < m; ++i) if ((s >> i) & 1) cnt ++;
66         if (cnt >= k) {
67             for (int i = 0; i <= Index; ++i) add(ans, dp[n][i][s]);
68         }
69     }
70     printf("%d\n",ans);
71 }
72 void init() {
73     Index = 0;
74     memset(ch, 0, sizeof(ch));
75     memset(sta, 0, sizeof(sta));
76     memset(dp, 0, sizeof(dp));
77     memset(fail, 0, sizeof(fail));
78 }
79 int main() {
80     int n, m, k;
81     while (~scanf("%d%d%d", &n, &m, &k)) {
82         if (!n && !m && !k) break;
83         init();
84         for (int i = 1; i <= m; ++i) {
85             scanf("%s", s); Insert(s, i - 1);
86         }
87         bfs();
88         solve(n, m, k);        
89     }
90     return 0;
91 }

 

posted @ 2018-12-09 10:01  MJT12044  阅读(147)  评论(0编辑  收藏  举报