HDU2243 考研路茫茫——单词情结 AC自动机DP矩阵优化

传送门:点击打开链接

考研路茫茫——单词情结

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3929    Accepted Submission(s): 1147


Problem Description
背单词,始终是复习英语的重要环节。在荒废了3年大学生涯后,Lele也终于要开始背单词了。
一天,Lele在某本单词书上看到了一个根据词根来背单词的方法。比如"ab",放在单词前一般表示"相反,变坏,离去"等。

于是Lele想,如果背了N个词根,那这些词根到底会不会在单词里出现呢。更确切的描述是:长度不超过L,只由小写字母组成的,至少包含一个词根的单词,一共可能有多少个呢?这里就不考虑单词是否有实际意义。

比如一共有2个词根 aa 和 ab ,则可能存在104个长度不超过3的单词,分别为
(2个) aa,ab,
(26个)aaa,aab,aac...aaz,
(26个)aba,abb,abc...abz,
(25个)baa,caa,daa...zaa,
(25个)bab,cab,dab...zab。

这个只是很小的情况。而对于其他复杂点的情况,Lele实在是数不出来了,现在就请你帮帮他。
 


Input
本题目包含多组数据,请处理到文件结束。
每组数据占两行。
第一行有两个正整数N和L。(0 第二行有N个词根,每个词根仅由小写字母组成,长度不超过5。两个词根中间用一个空格分隔开。
 


Output
对于每组数据,请在一行里输出一共可能的单词数目。
由于结果可能非常巨大,你只需要输出单词总数模2^64的值。
 


Sample Input
 
   
2 3 aa ab 1 2 a
 


Sample Output
 
   
104 52
 


Author
linle

题意:给出n个单词。问长度不超过m的串中,至少包含上述的至少一个单词的串的数目,对2^64取MOD

思路:这道题和POJ 2278比较相似,没有做过的请先参考http://blog.csdn.net/w703710691d/article/details/43271693

与POJ 2278最大的不同的,这道题要求得是长度不超过m的串。就要求得长度为1、2、3……m的符合要求串。可以参照POJ 2278的思路,先求出不符合的串,在用总数减去这个值,就得到了答案。下面设矩阵为A.中间会用到求A+A^2+A^3+……A^m【记为X】和26+26^2+26^3……+26^m次方的值。可以参考二分幂的方法。先求出(A+A^2+A^3……A^(m/2)【记为B】和A^(m/2)的值。那么X=(A^(m/2)+E)*B。E为单位阵。算数的也是同样的方法。将运算过程中的变量和矩阵的元素定义为unsigned __int64,就能实现自动对2^64自动取MOD

代码:

#pragma comment(linker, "/STACK:102400000,102400000")
#include
#include
#define SIGMA_SIZE 26
#define maxn 40
#include
#define uLL unsigned __int64
using namespace std;
int ch[maxn][SIGMA_SIZE];
int val[maxn];
int last[maxn], f[maxn];
int cnt;
inline int idx(char c)
{
	return c - 97;
}
void insert(char s[])
{
	int len = strlen(s);
	int u = 0;
	for (int i = 0; i bin(Matrix a, int k)
{
	pair tmp, res;
	if (k == 0)
	{
		return make_pair(ZERO(a.r), ONE(a.r));
	}
	else if (k == 1)
		return make_pair(a, a);
	tmp = bin(a, k >> 1);
	res.first = (tmp.second + ONE(a.r))*tmp.first;
	res.second = tmp.second*tmp.second;
	if (k & 1)
	{
		res.second = res.second*a;
		res.first = res.first + res.second;
	}
	return res;
}
bool vis[maxn];
int mp[maxn][maxn];
void bfs()
{
	memset(vis, 0, sizeof(vis));
	vis[0] = 1;
	queueq;
	q.push(0);
	while (!q.empty())
	{
		int u = q.front();
		q.pop();
		for (int i = 0; i<26; i++)
		{
			int p = u;
			while (p&&!ch[p][i]) p = f[p];
			p = ch[p][i];
			if (val[p]) continue;
			if (last[p]) continue;
			mp[u][p]++;
			if (!vis[p]) q.push(p);
			vis[p] = 1;
		}
	}
}
pair bin(uLL a, int k)
{
	if (k == 1) return make_pair(a, a);
	else if (k == 0) return (make_pair(0, 1));
	pairtmp, res;
	tmp = bin(a, k >> 1);
	res.first = (tmp.second + 1)*tmp.first;
	res.second = tmp.second*tmp.second;
	if (k & 1)
	{
		res.second = res.second*a;
		res.first = res.first + res.second;
	}
	return res;
}
void slove(uLL m)
{
	memset(mp, 0, sizeof(mp));
	bfs();
	Matrix tmp;
	tmp.r = cnt;
	tmp.c = cnt;
	for (int i = 0; i <= cnt; i++)
		for (int j = 0; j <= cnt; j++) tmp.g[i][j] = mp[i][j];
	pair res;
	res = bin(tmp, m);
	uLL ans = 0;
	for (int i = 0; i <= cnt; i++) ans += res.first.g[0][i];
	ans = bin(26, m).first - ans;
	printf("%I64u\n", ans);
}
void getFail()
{
	queueq;
	f[0] = 0;
	for (int c = 0; c
可能会栈溢出,所以我直接交了C++




你可能感兴趣的:(数据结构,DP)