[JSOI2007]文本生成器

容斥原理, 求出所有的情况减去不可读的情况就是可读的文本数了a
找不可读文本的数量类似于病毒那一题趴我觉得
DP转移的话...
用f[i][j] 表示当前在节点j, 且串长为i时的情况

#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e4 + 7;
const int N = 20005;

int n, m, cnt;
int f[N][10000];//f[i][j] : 当前在节点j, 且串长为i时的情况
struct {
	int vis[26];
	int fail;
	int end;
} AC[N];

void build(string s) {
	int now = 0;
	for(int i = 0; i < s.size(); i++) {
		if(!AC[now].vis[s[i] - 'A']) 
			AC[now].vis[s[i] - 'A'] = ++cnt;
		now = AC[now].vis[s[i] - 'A'];
	}
	AC[now].end = 1;
}
void Get_fail() {
	queue<int> q;
	for(int i = 0; i < 26; i++) 
		if(AC[0].vis[i]) {
			AC[AC[0].vis[i]].fail = 0;
			q.push(AC[0].vis[i]);
		}
	while(!q.empty()) {
		int u = q.front(); q.pop();
		for(int i = 0; i < 26; i++) {
			if(AC[u].vis[i]) {
				AC[AC[u].vis[i]].fail = AC[AC[u].fail].vis[i];
				AC[AC[u].vis[i]].end |= AC[AC[AC[u].vis[i]].fail].end;
				q.push(AC[u].vis[i]);
			}
			else AC[u].vis[i] = AC[AC[u].fail].vis[i];
		}
	}
}
int main() {
	ios :: sync_with_stdio(0);

	string s;
	cin >> n >> m;
	for(int i = 1; i <= n; i++)
		cin >> s, build(s);
	Get_fail();	
	f[0][0] = 1;
	for(int i = 1; i <= m; i++) 
		for(int j = 0; j <= cnt; j++) 
			for(int k = 0; k < 26; k++) 
				if(!AC[AC[j].vis[k]].end)
					(f[i][AC[j].vis[k]] += f[i - 1][j] ) %= MOD;
	int ans = 0;
	for(int i = 0; i <= cnt; i++)
		(ans += f[m][i] ) %= MOD;
	int sum = 26;
	for(int i = 1; i < m; i++)
		(sum *= 26) %= MOD;
	cout << (sum - ans + MOD) % MOD;
	return 0;
}
posted @ 2020-10-27 10:10  月夭  阅读(64)  评论(0编辑  收藏  举报