• [bzoj1030] [JSOI2007]文本生成器


    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考试差不多了。

    (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
    ",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;
    }
    
  • 相关阅读:
    第18课 类型萃取(2)_获取返回值类型的traits
    第17课 类型萃取(1)_基本的type_traits
    【ASP.NET MVC系列】浅谈数据注解和验证
    【ASP.NET MVC系列】浅谈NuGet在VS中的运用
    【ASP.NET MVC系列】浅谈ASP.NET MVC 视图
    【ASP.NET MVC系列】浅谈ASP.NET MVC运行过程
    【Java系列】Eclipse与Tomcat
    【java系列】java开发环境搭建
    【设计模式篇】工厂模式
    【架构篇】OCP和依赖注入
  • 原文地址:https://www.cnblogs.com/hbyer/p/10359728.html
Copyright © 2020-2023  润新知