只要你跑的够快,锅就追不上你

0%

「ZOJ 3494」BCD Code(AC 自动机 + 动态规划)

题目大意

「ZOJ 3494」BCD Code

定义一个数的 BCD Code 是它的每个数码的 $4$ 位二进制表示拼接起来。给定 $n$ 个长度不超过 $20$ 的禁忌串和两个正整数 $A, B$,问 $A, B$ 之间有多少数的 BCD Code 不包含禁忌串。

数据范围:$n \le 100, A, B \le 10^{200}$。

思路分析

AC 自动机 + 数位 DP

这里纯粹只是为了贴(两)个板子。

代码实现

1
#include <cstdio>
2
#include <cstring>
3
#include <queue>
4
using namespace std;
5
6
const int maxn = 200, maxm = 2e3, mod = 1e9 + 9;
7
const char *str[] = { "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001" };
8
int T, n, m, tot, ch[maxm + 3][2], mrk[maxm + 3], fail[maxm + 3], dp[maxn + 3][maxm + 3][2][2];
9
char s[maxn + 3];
10
11
void clear(int x) {
12
	ch[x][0] = ch[x][1] = mrk[x] = fail[x] = 0;
13
}
14
15
void insert(char s[], int n) {
16
	int x = 1;
17
	for (int i = 1; i <= n; i++) {
18
		if (!ch[x][s[i] - '0']) {
19
			clear(++tot);
20
			ch[x][s[i] - '0'] = tot;
21
		}
22
		x = ch[x][s[i] - '0'];
23
	}
24
	mrk[x] = 1;
25
}
26
27
void build() {
28
	queue<int> Q;
29
	for (int i = 0; i < 2; i++) {
30
		if (ch[1][i]) {
31
			fail[ch[1][i]] = 1;
32
			Q.push(ch[1][i]);
33
		} else {
34
			ch[1][i] = 1;
35
		}
36
	}
37
	while (!Q.empty()) {
38
		int u = Q.front();
39
		Q.pop();
40
		mrk[u] |= mrk[fail[u]];
41
		for (int i = 0; i < 2; i++) {
42
			if (ch[u][i]) {
43
				fail[ch[u][i]] = ch[fail[u]][i];
44
				Q.push(ch[u][i]);
45
			} else {
46
				ch[u][i] = ch[fail[u]][i];
47
			}
48
		}
49
	}
50
}
51
52
void add(int &x, int y) {
53
	x = (x + y < mod ? x + y : x + y - mod);
54
}
55
56
int solve(char s[], int n) {
57
	memset(dp, 0, sizeof(dp));
58
	dp[0][1][1][1] = 1;
59
	for (int i = 1; i <= n; i++) {
60
		for (int j = 1; j <= tot; j++) {
61
			for (int k = 0; k < 2; k++) {
62
				for (int l = 0; l < 2; l++) {
63
					if (!dp[i - 1][j][k][l]) continue;
64
					for (int x = 0; x <= (k ? s[i] - '0' : 9); x++) {
65
						bool flag = true;
66
						int u = j;
67
						if (!l || x) {
68
							const char *s = str[x];
69
							for (int t = 0; t < 4; t++) {
70
								u = ch[u][s[t] - '0'];
71
								if (mrk[u]) flag = false;
72
							}
73
						}
74
						if (flag) {
75
							add(dp[i][u][k && (x == s[i] - '0')][l && x == 0], dp[i - 1][j][k][l]);
76
						}
77
					}
78
				}
79
			}
80
		}
81
	}
82
	int ans = 0;
83
	for (int i = 1; i <= tot; i++) {
84
		for (int j = 0; j < 2; j++) {
85
			add(ans, dp[n][i][j][0]);
86
		}
87
	}
88
	return ans;
89
}
90
91
int main() {
92
	scanf("%d", &T);
93
	while (T--) {
94
		scanf("%d", &n);
95
		tot = 1, clear(1);
96
		for (int i = 1; i <= n; i++) {
97
			scanf("%s", s + 1);
98
			m = strlen(s + 1);
99
			insert(s, m);
100
		}
101
		build();
102
		scanf("%s", s + 1);
103
		m = strlen(s + 1);
104
		for (int i = m; i; i--) {
105
			if (s[i] == '0') {
106
				s[i] = '9';
107
			} else {
108
				s[i]--;
109
				break;
110
			}
111
		}
112
		if (s[1] == '0') {
113
			m--;
114
			for (int i = 1; i <= m; i++) {
115
				s[i] = s[i + 1];
116
			}
117
		}
118
		int ans = -solve(s, m);
119
		scanf("%s", s + 1);
120
		m = strlen(s + 1);
121
		ans += solve(s, m);
122
		ans < 0 ? ans += mod : 0;
123
		printf("%d\n", ans);
124
	}
125
	return 0;
126
}