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\n",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;
}
posted @ 2020-04-19 11:06  wxyww  阅读(106)  评论(0编辑  收藏  举报