HDU 2825 Wireless Password AC自动机 + DP

HDU 2825
  1 /*
2 * hdu 2825 Wireless Password
3 * —— 2011-11-10/15:41 开始敲
4 * —— 2011-11-10/16:27 结束敲
5 * —— 2011-11-10/20:10 靠柯神Debug成功
6 *
7 * 题意:
8 * 给定1个有m(m<=10)个字符串(长度<=10)的集合,
9 * 从其中取不少于k个串(k<=m),拼成一个长为n的串,
10 * 这个串可以互相重叠,问有多少种组合。(答案%20090717)
11 *
12 * 思路:
13 * dp[i][j][k]:当前长为i的串走到Trie图上的j号节点,
14 * 已取k状态(位表示取了哪些串)时,最多能有多少方案
15 * 转移方程:dp[i+1][child[j].id][k|child[j].tag] += dp[i][j][k]
16 *
17 * 复杂度:O(n * m * 2^m * 字符集大小) 其中2^m用来状态压缩
18 *
19 * 错误:
20 * 1. inti_root()中没有对root和tot进行初始化 = =
21 * 2. 才发现原来的一个重大错误,我在进行DP的时候,
22 * 其实没有DP到底,循环第二维的时候少了一个等号,
23 * Trie图上的最后一个节点没走到,做POJ-3691却过了,
24 * POJ的数据果然不够强大
25 */
26
27 #include <stdio.h>
28 #include <iostream>
29 #include <string.h>
30 #include <math.h>
31 using namespace std;
32
33 #define N 105
34 #define cls(a, b) memset(a, b, sizeof(a))
35 #define begin 'a'
36 #define kind 26
37 #define MOD 20090717
38
39 int root, tot;
40 int que[N], head, tail;
41 int f[30][N][1030];
42 int map[1030];
43
44 struct node{
45 int ch[kind], tag, fail;
46 void init(){ cls(ch, 0); tag = 0; fail = -1; }
47 }T[N];
48
49 void init_root()
50 {
51 root = tot = 0;
52 T[root].init();
53 }
54 void insert(char *s, int id)
55 {
56 int p = root, idx;
57 while(*s)
58 {
59 idx = *(s++) - begin;
60 if(!T[p].ch[idx])
61 {
62 T[++tot].init();
63 T[p].ch[idx] = tot;
64 }
65 p = T[p].ch[idx];
66 }
67 T[p].tag |= (1<<id);
68 }
69 void build_AC()
70 {
71 head = tail = 0;
72 que[tail++] = root;
73 while(head < tail)
74 {
75 int u = que[head++];
76 for(int i=0; i<kind; i++)
77 {
78 if(T[u].ch[i])
79 {
80 int son = T[u].ch[i];
81 int p = T[u].fail;
82 if(u == root)
83 T[son].fail = root;
84 else{
85 T[son].fail = T[p].ch[i];
86 T[son].tag |= T[T[p].ch[i]].tag; //传递标记
87 }
88 que[tail++] = son;
89 }else{
90 if(u == root) T[u].ch[i] = root;
91 else T[u].ch[i] = T[T[u].fail].ch[i];
92 }
93 }
94 }
95 }
96 void init_map()
97 {
98 int d = 1<<10;
99 map[0] = 0;
100 for(int i=1; i<d; i++)
101 map[i] = map[i>>1] + (i&1);
102 }
103 void solve()
104 {
105 int n, m, d, i, j, k, t, mx, son, tag;
106 char str[50];
107 init_map();
108 while(~scanf("%d%d%d", &n, &m, &t) && (n||m||t))
109 {
110 init_root();
111 for(i=0; i<m; i++)
112 {
113 scanf("%s", str);
114 insert(str, i);
115 }
116 build_AC();
117 mx = 1 << m;
118 cls(f, 0);
119 f[0][0][0] = 1;
120 for(i=0; i<n; i++)
121 for(j=0; j<=tot; j++) //因为这个等号的问题内伤了
122 for(k=0; k<mx; k++)
123 {
124 if(!f[i][j][k]) continue;
125 for(d=0; d<kind; d++)
126 {
127 son = T[j].ch[d];
128 tag = T[son].tag;
129 f[i+1][son][k|tag] += f[i][j][k];
130 if(f[i+1][son][k|tag] >= MOD)
131 f[i+1][son][k|tag] %= MOD;
132 }
133 }
134 int sum = 0;
135 for(i=0; i<=tot; i++)
136 for(j=0; j<mx; j++)
137 {
138 if(map[j]>=t) {
139 sum+=f[n][i][j];
140 if(sum >= MOD) sum %= MOD;
141 }
142 }
143 printf("%d\n", sum);
144 }
145 }
146
147 int main()
148 {
149 #ifdef Nstd
150 freopen("E:\\workspace\\in.txt", "r+", stdin);
151 #endif
152 solve();
153 return 0;
154 }

题外话,昨晚弄到1点多才回去的,一路上和P神、柯神聊到寝室楼下。大门紧闭,沙茶的我们以为门锁了,去按了一下门铃,按完才发现其实没锁。。

赶紧一溜烟地跑回了楼上,留下大叔独自在门卫室黯然神伤。。 大叔对不住了!!!

原文地址:https://www.cnblogs.com/Nstd/p/2244923.html