[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 }