[BZOJ1030] [JSOI2007]文本生成器(AC自动机 + DP)

传送门

 

dp没怎么理解好。。。QAQ

f[i][j]表示长度为i,当前节点为j的方案数

 

——代码

#include <queue>
#include <cstdio>
#include <cstring>
#define N 100001
#define p 10007

int n, m, cnt, ans, sum = 1;
int next[N][26], fail[N], f[101][N];
bool val[N];
char s[N];
std::queue <int> q;

inline void insert()
{
	int i, x, now = 0, m = strlen(s + 1);
	for(i = 1; i <= m; i++)
	{
		x = s[i] - 'A';
		if(!next[now][x])
			next[now][x] = ++cnt;
		now = next[now][x];
	}
	val[now] = 1;
}

inline void make_fail()
{
	int i, now;
	for(i = 0; i < 26; i++)
		if(next[0][i])
			q.push(next[0][i]);
	while(!q.empty())
	{
		now = q.front();
		q.pop();
		for(i = 0; i < 26; i++)
		{
			if(!next[now][i])
			{
				next[now][i] = next[fail[now]][i];
				continue;
			}
			fail[next[now][i]] = next[fail[now]][i];
			val[next[now][i]] |= val[next[fail[now]][i]];
			q.push(next[now][i]);
		}
	}
}

int main()
{
	int i, j, k;
	scanf("%d %d", &n, &m);
	for(i = 1; i <= n; i++)
	{
		scanf("%s", s + 1);
		insert();
	}
	make_fail();
	for(i = 1; i <= m; i++) sum = (sum * 26) % p;
	f[0][0] = 1;
	for(i = 1; i <= m; i++)
		for(j = 0; j <= cnt; j++)
		{
			if(val[j] || !f[i - 1][j]) continue;
			for(k = 0; k < 26; k++)
				if(!val[next[j][k]])
					f[i][next[j][k]] = (f[i][next[j][k]] + f[i - 1][j]) % p;
		}
	for(i = 0; i <= cnt; i++)
		if(!val[i])
			ans = (ans + f[m][i]) % p;
	printf("%d\n", ((sum - ans) % p + p) % p);
	return 0;
}

  

posted @ 2017-06-12 10:04  zht467  阅读(163)  评论(0编辑  收藏  举报