【BZOJ 3530】【SDOI 2014】数数

http://www.lydsy.com/JudgeOnline/problem.php?id=3530
上午gty的测试题,爆0了qwq
类似文本生成器那道题,把AC自动机的转移建出来,准确地说建出了一个Trie图,然后在上面dp就可以了。
这道题因为有小于等于n的限制,所以要用类似数位dp的方法,记录卡不卡上界两个状态来转移。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int N = 1203;

int ch[N][10], tot = 1, end[N];

void insert(char *s) {
	int len = strlen(s), x, tmp = 1, f;
	for (int i = 0; i < len; ++i) {
		x = s[i] - '0';
		if (ch[tmp][x]) tmp = ch[tmp][x];
		else tmp = ch[tmp][x] = ++tot;
	}
	end[tmp] = 1;
}

int qu[N], fail[N];
void BFS() {
	int x, f, v, p = 0, q = 1; qu[1] = 1;
	while (p != q) {
		x = qu[++p];
		for (int i = 0; i <= 9; ++i)
			if (v = ch[x][i]) {
				f = fail[x];
				while (f && ch[f][i] == 0) f = fail[f];
				fail[v] = f ? ch[f][i] : 1;
				qu[++q] = v;
			}
	}
	for (int i = 1; i <= q; ++i) {
		x = qu[i];
		for (int i = 0; i <= 9; ++i)
			if (!ch[x][i])
				ch[x][i] = ch[fail[x]][i];
	}
}

char s[N], c[N];
int m, f1[N], f2[N], f3[N], f4[N], r[N];

const int p = 1000000007;

int main() {
	scanf("%s", s + 1);
	scanf("%d", &m);
	for (int i = 1; i <= m; ++i) {
		scanf("%s", c);
		insert(c);
	}
	for (int i = 0; i < 10; ++i) if (ch[1][i] == 0) ch[1][i] = ++tot;
	BFS();
	int *pre0 = f1, *pre1 = f2, *now0 = f3, *now1 = f4;
	int len = strlen(s + 1);
	for (int i = 1; i <= len; ++i) r[i] = s[i] - '0';
	for (int tmp = 1; tmp <= len; ++tmp) {
		swap(pre0, now0); swap(pre1, now1);
		memset(now0, 0, sizeof(int) * (tot + 1));
		memset(now1, 0, sizeof(int) * (tot + 1));
		if (tmp == 1) {
			if (end[ch[1][r[tmp]]] == 0)
				(++now1[ch[1][r[tmp]]]) %= p;
			for (int i = r[tmp] - 1; i >= 1; --i)
				if (end[ch[1][i]] == 0)
					(++now0[ch[1][i]]) %= p;
		} else {
			for (int i = 9; i >= 1; --i)
				if (end[ch[1][i]] == 0)
					(++now0[ch[1][i]]) %= p;
		}
		for (int i = 2; i <= tot; ++i) {
			for (int j = 0; j < 10; ++j)
				if (end[ch[i][j]] == 0)
					(now0[ch[i][j]] += pre0[i]) %= p;
			if (end[ch[i][r[tmp]]] == 0)
				(now1[ch[i][r[tmp]]] += pre1[i]) %= p;
			for (int j = r[tmp] - 1; j >= 0; --j)
				if (end[ch[i][j]] == 0)
					(now0[ch[i][j]] += pre1[i]) %= p;
		}
	}
	
	int ans = 0;
	for (int i = 1; i <= tot; ++i) {
		ans = (ans + now0[i]) % p;
		ans = (ans + now1[i]) % p;
	}
	printf("%d\n", ans);
	return 0;
}
posted @ 2017-01-19 15:39  abclzr  阅读(197)  评论(0编辑  收藏  举报