[Bzoj1030][JSOI2007]文本生成器(AC自动机&dp)

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1030

最最最常见的多串匹配问题!题目求至少包含一个子串的方案数,则可以转化成全部方案-不包含子串的方案数。

求不包含任何字串的方案数即以所有子串建AC自动机,然后跑dp,dp[i][j]表示长度为i,在AC自动机上标号为j的点的子串方案数。

$ans=\sum_{i=0}^{len-1} dp[n][i]$,len为AC自动机节点编号。

最后用总方案数-ans即为最后答案。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 2e5 + 10;
 4 typedef long long ll;
 5 const int mod = 10007;
 6 struct node {
 7     int AC[60010][26];
 8     int End[60010];
 9     int fail[60010];
10     int dp[110][60010];
11     int len, root;
12     int newcode() {
13         memset(AC[len], -1, sizeof(AC[len]));
14         End[len] = 0;
15         len++;
16         return len - 1;
17     }
18     void init() {
19         len = 0;
20         root = newcode();
21     }
22     void build(string s) {
23         int k = s.size();
24         int now = root;
25         for (int i = 0; i < k; i++) {
26             if (AC[now][s[i] - 'A'] == -1)
27                 AC[now][s[i] - 'A'] = newcode();
28             now = AC[now][s[i] - 'A'];
29         }
30         End[now] = 1;
31     }
32     void getFail() {
33         queue<int>q;
34         fail[root] = root;
35         for (int i = 0; i < 26; i++) {
36             if (AC[root][i] != -1) {
37                 fail[AC[root][i]] = root;
38                 q.push(AC[root][i]);
39             }
40             else
41                 AC[root][i] = root;
42         }
43         while (!q.empty()) {
44             int now = q.front();
45             q.pop();
46             End[now] |= End[fail[now]];
47             for (int i = 0; i < 26; i++) {
48                 if (AC[now][i] != -1) {
49                     fail[AC[now][i]] = AC[fail[now]][i];
50                     q.push(AC[now][i]);
51                 }
52                 else
53                     AC[now][i] = AC[fail[now]][i];
54             }
55         }
56     }
57     int solve(int n) {
58         for (int i = 1; i <= n; i++)
59             for (int j = 0; j <= len; j++)
60                 dp[0][0] = 0;
61         dp[0][0] = 1;
62         for (int i = 1; i <= n; i++) {
63             for (int j = 0; j < len; j++) {
64                 for (int k = 0; k < 26; k++) {
65                     if (End[AC[j][k]] == 1)
66                         continue;
67                     dp[i][AC[j][k]] += dp[i - 1][j];
68                     dp[i][AC[j][k]] %= mod;
69                 }
70             }
71         }
72         int ans = 0;
73         for (int i = 0; i < len; i++)
74             ans = (ans + dp[n][i]) % mod;
75         return ans;
76     }
77 }AC;
78 int main() {
79     string s;
80     int n, m;
81     scanf("%d%d", &n, &m);
82     AC.init();
83     for (int i = 1; i <= n; i++) {
84         cin >> s;
85         AC.build(s);
86     }
87     AC.getFail();
88     int ans = AC.solve(m);
89     int sum = 1;
90     for (int i = 1; i <= m; i++)
91         sum = sum * 26 % mod;
92     printf("%d\n", (sum - ans + mod) % mod);
93 }

 

posted @ 2019-07-04 20:02  祈梦生  阅读(86)  评论(0编辑  收藏