1030: [JSOI2007]文本生成器

1030: [JSOI2007]文本生成器

https://www.lydsy.com/JudgeOnline/problem.php?id=1030

分析:

  AC自动机+dp。

  正难则反,求满足的,可以求出不满足的,用总的减去。所以考虑如何就出所有的长度为m的串里,没有出现任何一个单词的个数。

  建立AC自动机,然后会有一些点是一定不能走的,这些点要么是某些单词的结尾,或者是包含了某些单词(以它结尾的串的后缀是一个单词)。

  然后f[i][j]表示当前有多少位,在AC自动机的哪个位置的方案数。枚举下一位是什么,在AC自动机上转移。(注意,可能有许多点有些字符没有边,那么经过了这个字符也是合法的。这些的点贡献也要算上。假设存在这个点,直接转移即可。)

代码:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<iostream>
 6 #include<cctype>
 7 #include<set>
 8 #include<vector>
 9 #include<queue>
10 #include<map>
11 #define fi(s) freopen(s,"r",stdin);
12 #define fo(s) freopen(s,"w",stdout);
13 using namespace std;
14 typedef long long LL;
15
16 inline int read() {
17     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch==‘-‘)f=-1;
18     for(;isdigit(ch);ch=getchar())x=x*10+ch-‘0‘;return x*f;
19 }
20
21 const int N = 105;
22 const int C = 200005;
23 const int mod = 10007;
24
25 char s[N];
26 int f[N][C], ch[C][26], val[C], fail[C], q[C], Index, n, m;
27
28 void Insert(char *s) {
29     int u = 0, len = strlen(s + 1);
30     for (int i=1; i<=len; ++i) {
31         int c = s[i] - ‘A‘;
32         if (!ch[u][c]) ch[u][c] = ++Index;
33         u = ch[u][c];
34     }
35     val[u] = 1;
36 }
37 void build() {
38     int L = 1, R = 0; fail[0] = 0;
39     for (int c=0; c<26; ++c) {
40         int u = ch[0][c];
41         if (u) fail[u] = 0, q[++R] = u;
42     }
43     while (L <= R) {
44         int u = q[L ++];
45         for (int c=0; c<26; ++c) {
46             int v = ch[u][c];
47             if (!v) {
48                 ch[u][c] = ch[fail[u]][c]; continue; // !!!
49             }
50             q[++R] = v;
51             int p = fail[u];
52             while (p && !ch[p][c]) p = fail[p];
53             fail[v] = ch[p][c];
54             val[v] = val[v] ? val[v] : val[fail[v]];
55         }
56     }
57 }
58 void dp() {
59     f[0][0] = 1;
60     for (int i=0; i<m; ++i) {
61         for (int j=0; j<=Index; ++j) {
62             if (val[j] || !f[i][j]) continue;
63             for (int c=0; c<26; ++c) { // 不仅要走存在的,也要走不存在的点,存在的点不能走有标记的。
64                 (f[i + 1][ch[j][c]] += f[i][j]) %= mod;
65             }
66         }
67     }
68 }
69 int main() {
70     n = read(), m = read();
71     for (int i=1; i<=n; ++i) {
72         scanf("%s", s + 1);
73         Insert(s);
74     }
75     build();
76     dp();
77     int ans = 1;
78     for (int i=1; i<=m; ++i) ans = (ans * 26) % mod;
79     for (int j=0; j<=Index; ++j)
80         if (!val[j]) ans = (ans - f[m][j] + mod) % mod;
81     cout << ans;
82     return 0;
83 }

原文地址:https://www.cnblogs.com/mjtcn/p/9726314.html

时间: 2024-10-07 05:47:15

1030: [JSOI2007]文本生成器的相关文章

bzoj 1030: [JSOI2007]文本生成器 (ac自己主动机上的dp)

1030: [JSOI2007]文本生成器 Time Limit: 1 Sec  Memory Limit: 162 MB Submit: 2635  Solved: 1090 [Submit][Status][Discuss] Description JSOI交给队员ZYX一个任务.编制一个称之为"文本生成器"的电脑软件:该软件的使用者是一些低幼人群,他们如今使用的是GW文本生成器v6版.该软件能够随机生成一些文章―――总是生成一篇长度固定且全然随机的文章-- 也就是说,生成的文章中

BZOJ 1030: [JSOI2007]文本生成器( AC自动机 + dp )

之前一直没调出来T^T...早上刷牙时无意中就想出错在哪里了... 对全部单词建AC自动机, 然后在自动机上跑dp, dp(i, j)表示匹配到了第i个字符, 在自动机上的j结点的方案数, 然后枚举A~Z进行转移. -------------------------------------------------------------------------- #include<bits/stdc++.h> using namespace std; #define idx(c) ((c) -

bzoj 1030 [JSOI2007]文本生成器(AC自动机+DP)

1030: [JSOI2007]文本生成器 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 3059  Solved: 1255[Submit][Status][Discuss] Description JSOI交给队员ZYX一个任务,编制一个称之为“文本生成器”的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版.该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文章—— 也就是说,生成的文章中每个字节都是完

bzoj 1030: [JSOI2007]文本生成器 (ac自动机上的dp)

1030: [JSOI2007]文本生成器 Time Limit: 1 Sec  Memory Limit: 162 MB Submit: 2635  Solved: 1090 [Submit][Status][Discuss] Description JSOI交给队员ZYX一个任务,编制一个称之为"文本生成器"的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版.该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文章-- 也就是说,生成的文章中

【BZOJ】1030: [JSOI2007]文本生成器(递推+ac自动机)

http://www.lydsy.com/JudgeOnline/problem.php?id=1030 其实做了1009也不会感到很难了,无非将kmp变成了ac自动机. 设f[i,j]表示前i个串当前匹配到j的节点的方案数.. 然后自己想. sb错1:ac自动机的节点开小了(自己想错了..以为最多节点就是层数×分支(26)....于是..其实是n个串的长度和...) sb错2:ac自动机bfs时没有维护信息啊!!只维护了一个fail... #include <cstdio> #include

BZOJ 1030 [JSOI2007]文本生成器(AC自动机)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1030 [题目大意] 求出包含任意一个给定串的串数量 [题解] 我们求出不包含任意一个给定串的数量,用全集去减即可, 对于给定串建立AC自动机,用1节点作为根,0节点向1连全字符集转移作为超级源, 那么0->match能匹配所有不包含给定串的串, 记dp[i][j]表示匹配了i长度,匹配到AC自动机j节点的串数量, 统计之后取补集即可. [代码] #include <cstdio&g

bzoj 1030: [JSOI2007]文本生成器

AC自动机的fail,然后用fail搞搞DP,不懂不懂,,,,啊啊啊啊啊啊 1 #include<bits/stdc++.h> 2 #define N 1000005 3 #define LL long long 4 #define inf 0x3f3f3f3f 5 using namespace std; 6 inline int ra() 7 { 8 int x=0,f=1; char ch=getchar(); 9 while (ch<'0' || ch>'9') {if (

【BZOJ 1030】 [JSOI2007]文本生成器

1030: [JSOI2007]文本生成器 Time Limit: 1 Sec  Memory Limit: 162 MB Submit: 2017  Solved: 834 [Submit][Status] Description JSOI交给队员ZYX一个任务,编制一个称之为"文本生成器"的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版.该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文章-- 也就是说,生成的文章中每个字节都是完全随机

BZOJ1030:[JSOI2007]文本生成器

1030: [JSOI2007]文本生成器 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 4859  Solved: 2019[Submit][Status][Discuss] Description JSOI交给队员ZGX一个任务,编制一个称之为"文本生成器"的电脑软件:该软件的使用者是一些战舰狗,他们现在使用的是GW文本生成器v6版.该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文章-- 也就是说,生成的文章中每个字