Loading

「刷题记录」[JSOI2007] 文本生成器

第一道 AC 自动机 + DP 题。

题目链接:P4052 [JSOI2007] 文本生成器 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

利用容斥原理的思想,答案就是所有串的数量减去不可读的串的数量。

\(dp \left(i, j \right)\) 表示串长为 \(i\),在 AC 自动机上走到编号为 \(j\) 时不经过单词结尾的路径条数。

转移方程:

该节点不是单词结尾状态:dp[i][ac[j].tr[c]] += dp[i - 1][j] % mod

这类题的状态十分固定,一般为 \(dp \left (i, j \right )\),表示串长为 \(i\),状态为 \(j\) 的情况。

代码:

/*
  The code was written by yifan, and yifan is neutral!!!
 */

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

template<typename T>
inline T read() {
	T x = 0;
	bool fg = 0;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		fg |= (ch == '-');
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 3) + (x << 1) + (ch ^ 48);
		ch = getchar();
	}
	return fg ? ~x + 1 : x;
}

const int N = 110;
const int M = 10010;
const int mod = 1e4 + 7;

int n, m, tot;
char s[N];
int dp[N][6010];
queue<int> q;

struct node {
	int fail, End;
	int tr[26];
} ac[M];

void Insert(char* s) {
	int l = strlen(s), u = 0;
	for (int i = 0; i < l; ++ i) {
		if (!ac[u].tr[s[i] - 'A']) {
			ac[u].tr[s[i] - 'A'] = ++ tot;
		}
		u = ac[u].tr[s[i] - 'A'];
	}
	ac[u].End = 1;
}

void get_fail() {
	for (int i = 0; i < 26; ++ i) {
		if (ac[0].tr[i]) {
			ac[ac[0].tr[i]].fail = 0;
			q.emplace(ac[0].tr[i]);
		}
	}
	while (!q.empty()) {
		int fr = q.front();
		q.pop();
		for (int i = 0; i < 26; ++ i) {
			if (ac[fr].tr[i]) {
				ac[ac[fr].tr[i]].fail = ac[ac[fr].fail].tr[i];
				ac[ac[fr].tr[i]].End |= ac[ac[ac[fr].tr[i]].fail].End;
				q.emplace(ac[fr].tr[i]);
			} else {
				ac[fr].tr[i] = ac[ac[fr].fail].tr[i];
			}
		}
	}
}

ll qpow(int x, int y) {
	ll ans = 1;
	while (y) {
		if (y & 1) {
			ans = ans * x % mod;
		}
		y >>= 1;
		x = x * x % mod;
	}
	return ans % mod;
}

int main() {
	n = read<int>(), m = read<int>();
	for (int i = 1; i <= n; ++ i) {
		scanf("%s", s + 1);
		Insert(s + 1);
	}
	get_fail();
	dp[0][0] = 1;
	for (int i = 1; i <= m; ++ i) {
		for (int j = 0; j <= tot; ++ j) {
			for (int k = 0; k < 26; ++ k) {
				if (!ac[ac[j].tr[k]].End) {
					dp[i][ac[j].tr[k]] = (dp[i - 1][j] + dp[i][ac[j].tr[k]]) % mod;
				}
			} 
		}
	}
	ll ans = qpow(26, m);
	for (int i = 0; i <= tot; ++ i) {
		ans = ((ans - dp[m][i]) % mod + mod) % mod;
	}
	printf("%lld\n", ans);
	return 0;
}
posted @ 2023-07-22 15:47  yi_fan0305  阅读(14)  评论(0编辑  收藏  举报