zoukankan      html  css  js  c++  java
  • 文本生成器[JSOI2007]

    【题目描述】

    JSOI 交给队员 ZYX 一个任务,编制一个称之为“文本生成器”的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是 GW 文本生成器 v6 版。

    该软件可以随机生成一些文章——总是生成一篇长度固定且完全随机的文章。 也就是说,生成的文章中每个字符都是完全随机的。如果一篇文章中至少包含使用者们了解的一个单词,那么我们说这篇文章是可读的(我们称文章 (t) 包含单词 (t),当且仅当单词 (t) 是文章 (s) 的子串)。但是,即使按照这样的标准,使用者现在使用的 GW 文本生成器 v6 版所生成的文章也是几乎完全不可读的。ZYX 需要指出 GW 文本生成器 v6 生成的所有文本中,可读文本的数量,以便能够成功获得 v7 更新版。你能帮助他吗?

    答案对 (10^4 + 7) 取模。

    【输入格式】

    第一行有两个整数,分别表示使用者了解的单词总数 (n) 和生成的文章长度 (m)

    接下来 (n) 行,每行一个字符串 (s_i),表示一个使用者了解的单词。

    【输出格式】

    输出一行一个整数表示答案对 (10^4 + 7) 取模的结果。

    题解

    首先 很容易想到 答案就是总的方案数,也就是(26^m)减去不合法的方案数

    不合法的方案数我们可以通过在AC自动机上面DP来求得

    先对于那(n)个串建好AC自动机

    显然,一个不合法的串在AC自动机上匹配时一定不会经过任何结束节点或者fail链上有结束节点的点

    所以我们先预处理哪些是这样的节点 这个是可以在求fail的时候顺便处理的

    然后设(dp[x][j])表示现在在AC自动机上节点(x)处,串长度为(j)的方案数

    转移方程:(dp[ch[x][c]][j+1]~ +!!= ~dp[x][j]) ((ch[x][c])不为结束节点),初始状态(dp[0][0]=1)

    #include <bits/stdc++.h>
    using namespace std;
    
    inline int read() {
    	int x = 0, f = 1; char ch = getchar();
    	for (; ch > '9' || ch < '0'; ch = getchar()) if (ch == '-') f = -1;
    	for (; ch <= '9' && ch >= '0'; ch = getchar()) x = (x << 3) + (x << 1) + (ch ^ '0');
    	return x * f;
    }
    
    const int mod = 10007;
    int n, m, dp[10005][205], ans;
    char s[205];
    
    struct AC_automaton{
    	int fail[10005], ch[10005][30], tot;
    	bool tag[10005];
    	
    	inline void insert(char *str, int len) {
    		int x = 0;
    		for (int i = 1; i <= len; i++) {
    			if (!ch[x][str[i]-'A']) ch[x][str[i]-'A'] = ++tot;
    			x = ch[x][str[i]-'A'];
    		}
    		tag[x] = 1;
    	}
    	
    	inline void getfail() {
    		queue<int> q;
    		for (int i = 0; i < 26; i++) if (ch[0][i]) q.push(ch[0][i]);
    		while (!q.empty()) {
    			int x = q.front(); q.pop();
    			tag[x] |= tag[fail[x]];
    			for (int i = 0; i < 26; i++) {
    				if (ch[x][i]) fail[ch[x][i]] = ch[fail[x]][i], q.push(ch[x][i]);
    				else ch[x][i] = ch[fail[x]][i];
    			}
    		}
    	}
    	
    	inline void DP() {
    		memset(dp, 0, sizeof(dp));
    		dp[0][0] = 1;
    		for (int i = 0; i < m; i++) {
    			for (int x = 0; x <= tot; x++) {
    				for (int c = 0; c < 26; c++) {
    					if (!tag[ch[x][c]]) {
    						dp[ch[x][c]][i+1] = (dp[ch[x][c]][i+1] + dp[x][i]) % mod;
    					}
    				}
    			}
    		}
    		ans = 1;
    		for (int i = 1; i <= m; i++) ans = ans * 26 % mod;
    		for (int x = 0; x <= tot; x++) {
    			ans = (ans - dp[x][m] + mod) % mod;
    		}
    	}
    } T;
    
    int main() {
    	n = read(), m = read();
    	for (int i = 1; i <= n; i++) {
    		scanf("%s", s + 1);
    		T.insert(s, strlen(s + 1)); 
    	}
    	T.getfail();
    	T.DP();
    	printf("%d
    ", ans);
    	return 0;
    } 
    
  • 相关阅读:
    swagger 兼容 docker 转发 配置
    rust 条件编译 Debug Release
    rust-must-know-crates-5ad8 100DayOfRust
    python C# DES 加密转换
    The Little Book of Rust Books
    swiper 禁止滑动
    uniapp自定义凸出的导航栏
    uniapp css实现双排菜单向左滑动
    uniapp开发公众号,微信设置字体大小后,禁止改变页面字体大小
    uniapp接口封装
  • 原文地址:https://www.cnblogs.com/ak-dream/p/AK_DREAM75.html
Copyright © 2011-2022 走看看