Description
JSOI 交给队员 ZYX 一个任务, 编制一个称之为 "文本生成器" 的电脑软件: 该软件的使用者是一些低幼人群, 他们现在使用的是 GW 文本生成器 v6 版. 该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文
章 -- 也就是说, 生成的文章中每个字节都是完全随机的. 如果一篇文章中至少包含使用者们了解的一个单词, 那么我们说这篇文章是可读的 (我们称文章 a 包含单词 b, 当且仅当单词 b 是文章 a 的子串). 但是, 即使按照这样的标准, 使用者现在使用的 GW 文本生成器 v6 版所生成的文章也是几乎完全不可读的?.ZYX 需要指出 GW 文本生成器 v6 生成的所有文本中可读文本的数量, 以便能够成功获得 v7 更新版. 你能帮助他吗?
Input
输入文件的第一行包含两个正整数, 分别是使用者了解的单词总数 N (<= 60),GW 文本生成器 v6 生成的文本固定长度 M; 以下 N 行, 每一行包含一个使用者了解的单词. 这里所有单词及文本的长度不会超过 100, 并且只可能包含英文大写字母 A..Z
Output
一个整数, 表示可能的文章总数. 只需要知道结果模 10007 的值.
- Sample Input
- 2 2 A B
- Sample Output
- 100
- Solution
\(AC\) 自动机上 \(dp\).
正难则反, 考虑统计不合法的字串.
先建出 \(AC\) 自动机, 然后这题其实就和 bzoj1009: [HNOI2008]GT 考试 https://lydsy.com/JudgeOnline/problem.php?id=1009 差不多了.
设 \(f[i][j]\) 表示长度为 \(i\) 的串, 最后一位在自动机上的第 \(j\) 个点, 然后枚举状态 , 转移给儿子就好了.
- #include<bits/stdc++.h>
- using namespace std;
- void read(int &x) {
- x=0;int f=1;char ch=getchar();
- for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
- for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
- }
- #define write(x) printf("%d\n",x)
- const int maxn = 2e4+10;
- const int mod = 10007;
- int n,m,f[102][maxn];
- char c[maxn];
- int qpow(int a,int x) {
- int res=1;
- for(;x;x>>=1,a=1ll*a*a%mod) if(x&1) res=1ll*res*a%mod;
- return res;
- }
- struct AC_automaton {
- int son[maxn][26],fail[maxn],tot,vis[maxn];
- void ins(char *s) {
- int len=strlen(s+1),now=0;
- for(int i=1,t;i<=len;i++) {
- if(!son[now][t=s[i]-'A']) son[now][t]=++tot;
- now=son[now][t];
- }vis[now]=1;
- }
- void build() {
- queue<int> q;for(int i=0;i<26;i++) if(son[0][i]) q.push(son[0][i]);
- while(!q.empty()) {
- int now=q.front();q.pop();
- for(int i=0;i<26;i++)
- if(son[now][i]) fail[son[now][i]]=son[fail[now]][i],q.push(son[now][i]);
- else son[now][i]=son[fail[now]][i];
- if(vis[fail[now]]) vis[now]=1;
- }
- }
- void solve() {
- f[0][0]=1;
- for(int i=0;i<m;i++)
- for(int j=0;j<=tot;j++) {
- if(vis[j]||!f[i][j]) continue;
- for(int k=0;k<26;k++) f[i+1][son[j][k]]=(f[i+1][son[j][k]]+f[i][j])%mod;
- }
- int ans=0;
- for(int i=0;i<=tot;i++) if(!vis[i]) ans=(ans+f[m][i])%mod;
- write((qpow(26,m)-ans+mod)%mod);
- }
- }AC;
- int main() {
- read(n),read(m);
- for(int i=1;i<=n;i++) scanf("%s",c+1),AC.ins(c);
- AC.build(),AC.solve();
- return 0;
- }
[bzoj1030] [JSOI2007] 文本生成器
来源: http://www.bubuko.com/infodetail-2949514.html