• bzoj1030 [JSOI2007]文本生成器


    题目链接

    solution

    正难则反√

    考虑如何计算长度为(m)的字符串中不包含所给集合中任意一个串的方案数。

    先将所给的所有串建出(AC)自动机。

    (f[i][j])表示长度为(i)的字符串,第(i)个位置对应(AC)自动机中的第j个位置且不包含所给集合中任意一个串的方案数。

    然后枚举每一位所填充的字符,转移即可。

    code

    /*
    * @Author: wxyww
    * @Date:   2020-04-19 10:30:01
    * @Last Modified time: 2020-04-19 10:51:41
    */
    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #include<ctime>
    using namespace std;
    typedef long long ll;
    const int N = 6010,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;
    }
    int trie[N][26],tot,bz[N],fail[N];
    char s[N];
    void insert() {
    	int n = strlen(s + 1);
    	int now = 0;
    	for(int i = 1;i <= n;++i) {
    		int x = s[i] - 'A';
    		if(!trie[now][x]) trie[now][x] = ++tot;
    		now = trie[now][x];
    	}
    	bz[now] = 1;
    }
    queue<int>q;
    
    void build() {
    	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();
    		for(int i = 0;i < 26;++i) {
    			if(!trie[u][i]) trie[u][i] = trie[fail[u]][i];
    			else {
    				if(bz[trie[fail[u]][i]]) bz[trie[u][i]] = 1;
    				fail[trie[u][i]] = trie[fail[u]][i],q.push(trie[u][i]);
    			}
    		}
    	}
    }
    int qm(int x,int y) {
    	int ret = 1;
    	for(;y;y >>= 1,x = x * x % mod)
    		if(y & 1) ret = ret * x % mod;
    	return ret;
    }
    int f[110][6010];
    int main() {
    	// freopen("1030/1.in","r",stdin);
    	int n = read(),m = read();
    	for(int i = 1;i <= n;++i) {
    		scanf("%s",s + 1);
    		// if(strlen(s + 1) > m) continue;
    		insert();
    	}
    	build();
    	// cout<<tot<<endl;
    	f[0][0] = 1;
    	
    	// for(int i = 0;i <= tot;++i) printf("%d %d
    ",i,bz[i]);
    
    	for(int i = 0;i < m;++i) {
    		for(int j = 0;j <= tot;++j) {
    			if(bz[j]) continue;
    			for(int k = 0;k < 26;++k) {
    				// if(!i && !j) puts("!!!");			
    				f[i + 1][trie[j][k]] += f[i][j];
    				f[i + 1][trie[j][k]] %= mod;
    			}
    		}
    	}
    	int ans = qm(26,m);
    	for(int i = 0;i <= tot;++i) {
    		if(bz[i]) continue;
    		ans -= f[m][i];
    		ans %= mod;
    	}
    	cout<<(ans + mod) % mod<<endl;
    
    	return 0;
    }
    
  • 相关阅读:
    软件测试工程师的素质
    软件测试阶段的划分
    如何去涉及测试用例
    如何判断测试结束
    Linux常用命令大全
    测试用例设计方法
    Web测试方法
    loadrunner
    谈谈重复性测试
    软件测试思维导图
  • 原文地址:https://www.cnblogs.com/wxyww/p/bzoj1030.html
Copyright © 2020-2023  润新知