zoukankan      html  css  js  c++  java
  • bzoj1030 文本生成器

    题目链接

    题意

    给出(n)个字符串,要构造一个长度为(m)的字符串(S),使得给出的(n)个字符串中至少有一个是(S)的子串。问方案数。

    思路

    (AC)自动机+(DP)
    考虑至少有一个是S的子串不好考虑。考虑用全部情况减去其中不包含任何一个字符串的情况。
    全部情况就是(26^m),然后考虑怎么求出不包含任何一个字符串的情况。
    (f[i][j])表示已经确定了(i)个字符,现在到了(AC)自动机的j位置的方案数。
    显然如果(j)位置是给出字符串的结尾或者沿着(fail)指针可以跳到给出字符串的结尾,那么就不能转移。其他的就可以转移到(f[i + 1][k])(k)(j)(AC)自动机上的一个儿子。
    最后答案就是(26^m-sumlimits_{i = 0}^{tot}f[m][i](i不是给出字符串的结尾))

    代码

    /*
    * @Author: wxyww
    * @Date:   2019-02-01 19:33:15
    * @Last Modified time: 2019-02-01 20:04:44
    */
    #include<cstring>
    #include<queue>
    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cmath>
    #include<ctime>
    #include<bitset>
    using namespace std;
    typedef long long ll;
    const int N = 6000 + 10,mod = 10007;
    ll read() {
    	ll x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9') {
    		if(c=='-') f=-1;
    		c=getchar();
    	}
    	while(c>='0'&&c<='9') {
    		x=x*10+c-'0';
    		c=getchar();
    	}
    	return x*f;
    }
    char s[110];
    queue<int>q;
    int trie[N][27],bz[N],fail[N],tot;
    void ins() {
    	int len = strlen(s + 1);
    	int now = 0;
    	for(int i = 1;i <= len;++i) {
    		int x = s[i] - 'A';
    		if(!trie[now][x]) trie[now][x] = ++tot;
    		now = trie[now][x];
    	}
    	bz[now] = 1;
    }
    void get_fail() {
    	for(int i = 0;i < 26;++i) if(trie[0][i]) q.push(trie[0][i]);
    	while(!q.empty()) {
    		int u = q.front();q.pop();
    		bz[u] |= bz[fail[u]];
    		for(int i = 0;i < 26;++i) {
    			if(trie[u][i]) fail[trie[u][i]] = trie[fail[u]][i],q.push(trie[u][i]);
    			else trie[u][i] = trie[fail[u]][i];
    		}
    	}
    }
    int qm(int x,int y) {
    	int ans = 1;
    	for(;y;y >>= 1,x = 1ll * x * x % mod) {
    		if(y & 1) ans = 1ll * ans * x % mod;
    	}
    	return ans;
    }
    int f[N][N];
    int main() {
    	int n = read(),m = read();
    	for(int i = 1;i <= n;++i) {
    		scanf("%s",s + 1);
    		ins();
    	}
    	get_fail();
    	f[0][0] = 1;
    
    	for(int i = 0;i < m;++i) {
    		for(int j = 0;j <= tot;++j) {
    			if(bz[j] || !f[i][j]) continue;
    			for(int k = 0;k < 26;++k) {
    				int z = trie[j][k];
    				f[i + 1][z] += f[i][j];
    				f[i + 1][z] >= mod ? f[i + 1][z] -= mod : 0;
    			}
    		}
    	}
    	int ans = qm(26,m);
    	for(int i = 0;i <= tot;++i) {
    		if(!bz[i]) ans = (ans - f[m][i] + mod) % mod;
    	}
    	cout<<ans;
    	return 0;
    }
    
  • 相关阅读:
    设计模式入门
    Spring Boot 日志
    Spring Boot入门
    Vue--过滤器、指令、插件
    CentOS7更换yum源
    CentOS7中修改运行级别
    Xshell进行远程登录
    Linux的目录结构详情
    通过VMware Tools配置Centos7与本地主机的共享文件夹(亲测)
    eclipse中的Git操作
  • 原文地址:https://www.cnblogs.com/wxyww/p/10346927.html
Copyright © 2011-2022 走看看