ZOJ 3494 BCD Code AC自动机+数位dp

Binary-coded decimal (BCD) is an encoding for decimal numbers in which each digit is represented by its own binary sequence. To encode a decimal number using the common BCD encoding, each decimal digit is stored in a 4-bit nibble:

Decimal:    0     1     2     3     4     5     6     7     8     9
BCD:     0000  0001  0010  0011  0100  0101  0110  0111  1000  1001

Thus, the BCD encoding for the number 127 would be:

 0001 0010 0111

We are going to transfer all the integers from A to B, both inclusive, with BCD codes. But we find that some continuous bits, named forbidden code, may lead to errors. If the encoding of some integer contains these forbidden codes, the integer can not be transferred correctly. Now we need your help to calculate how many integers can be transferred correctly.

Input

There are multiple test cases. The first line of input is an integer T ≈ 100 indicating the number of test cases.

The first line of each test case contains one integer N, the number of forbidden codes ( 0 ≤ N ≤ 100). Then N lines follow, each of which contains a 0-1 string whose length is no more than 20. The next line contains two positive integers A and B. Neither A or B contains leading zeros and 0 < A ≤ B < 10200.

Output

For each test case, output the number of integers between A and B whose codes do not contain any of the N forbidden codes in their BCD codes. For the result may be very large, you just need to output it mod 1000000009.

Sample Input

3
1
00
1 10
1
00
1 100
1
1111
1 100

Sample Output

3
9
98

 

题解:dp[i][j]表示到第i为状态为j的个数。

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
#define ll long long
const int mod = 1000000009;
const int maxm = 2005;
const int INF = 1e9 + 7;
int n, cnt;
int tr[maxm][2], fail[maxm], last[maxm], p[15][15], dp[205][maxm], d[maxm];
char str[maxm];
void init()
{
	memset(last, 0, sizeof(last));
	memset(tr, 0, sizeof(tr));
	memset(fail, 0, sizeof(fail));
	memset(dp, -1, sizeof(dp));
	cnt = 0;
}
int insert()
{
	int len = strlen(str);
	int now = 0;
	for (int i = 0;i < len;i++)
	{
		int num = str[i] - '0';
		if (!tr[now][num])
			tr[now][num] = ++cnt;
		now = tr[now][num];
	}
	last[now] = 1;
	return now;
}
void find_fail()
{
	int now;
	queue<int>q;
	for (int i = 0;i < 2;i++)
		if (tr[0][i]) q.push(tr[0][i]);
	while (!q.empty())
	{
		now = q.front();q.pop();
		last[now] |= last[fail[now]];
		for (int i = 0;i < 2;i++)
		{
			if (tr[now][i])
			{
				fail[tr[now][i]] = tr[fail[now]][i];
				q.push(tr[now][i]);
			}
			else tr[now][i] = tr[fail[now]][i];
		}
	}
}
int dfs(int pos, int now, int zero, int limit)
{
	if (pos == -1) return 1;
	if (!limit&&dp[pos][now] != -1)
		return dp[pos][now];
	int ans = 0, i = 0, k, j;
	if (pos > 0 && zero)
	{
		ans += (ans + dfs(pos - 1, 0, 1, limit&&d[pos] == 0)) % mod;
		i = 1;
	}
	k = limit ? d[pos] : 9;
	for (i;i <= k;i++)
	{
		int x = now;
		for (j = 3;j >= 0;j--)
		{
			x = tr[x][(i & (1 << j)) != 0];
			if (last[x]) break;
		}
		if (j == -1)
			ans = (ans + dfs(pos - 1, x, 0, limit&&i == k)) % mod;
	}
	if (!limit && !zero)
		dp[pos][now] = ans;
	return ans;
}
int query(int flag)
{
	int s = 0, len;
	len = strlen(str);
	for (int i = len - 1;i >= 0;i--)
		d[s++] = str[i] - '0';
	if (flag)
	{
		d[0]--;
		int i = 0;
		while (d[i] < 0)
			d[i] = 9, d[++i] --;
		if (d[len - 1] == 0 && len != 1) s--;
	}
	return dfs(len - 1, 0, 1, 1);
}
int main()
{
	int i, j, k, n, sum, ans, t;
	scanf("%d", &t);
	while(t--)
	{
		init();ans = 0;
		scanf("%d", &n);
		for (i = 1;i <= n;i++)
		{
			scanf("%s", str);
			insert();
		}
		find_fail();
		scanf("%s", str);
		ans -= query(1);
		scanf("%s", str);
		ans += query(0);
		ans = (ans%mod + mod) % mod;
		printf("%d\n", ans);
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值