[转] AC自动机模板 [HDU2825 Wireless Password]

题目点这里=-=直接下模板了(虽然我觉得不太像模板)

补一下注意事项:

字符串读入一定要用string 不能用char 试过一个数据 前者300ms 后者8000ms

/*HDU2825 Wireless Password*/
#include <cstdio>
#include <cstdlib>
#include <string>
#include <climits>
#include <iostream>   
#include <vector>
#include <set>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <sstream>
#include <map>
#include <cstring>
#include <queue>
using namespace std;
//MAX_NODE = StringNumber * StringLength
const int MAX_NODE = 101;//节点个数,一般字符形式的题26个
const int CHILD_NUM = 26;//特定题目需要
const int mod = 20090717;
class ACAutomaton {
private:
	int chd[MAX_NODE][CHILD_NUM];	          //每个节点的儿子,即当前节点的状态转移
	int val[MAX_NODE];				//记录题目给的关键数据
	int fail[MAX_NODE];				//传说中的fail指针
	int Q[MAX_NODE];				//队列,用于广度优先计算fail指针
	int ID[128];					//字母对应的ID
	int sz;						//已使用节点个数
	int dp[2][MAX_NODE][1 << 10];	          //特定题目需要
public:
	void Initialize()//初始化,计算字母对应的儿子ID,如:'a'->0 ... 'z'->25
	{
		fail[0] = 0;
		for (int i = 0 ; i < CHILD_NUM ; i ++) ID[i + 'a'] = i;
	}
	void Reset()//重新建树需先Reset
	{
		memset(chd[0] , 0 , sizeof(chd[0]));
		sz = 1;
	}
	void Insert(char *a,int key)//将权值为key的字符串a插入到trie中
	{
		int p = 0;
		for ( ; *a ; a ++)
		{
			int c = ID[*a];
			if (!chd[p][c])
			{
				memset(chd[sz],0,sizeof(chd[sz]));
				val[sz] = 0;
				chd[p][c] = sz ++;
			}
			p = chd[p][c];
		}
		val[p] = key;
	}
	void Construct()//建立AC自动机,确定每个节点的权值以及状态转移
	{
		int *s = Q , *e = Q;
		for (int i = 0 ; i < CHILD_NUM ; i ++)
			if (chd[0][i])
			{
				fail[chd[0][i]] = 0;
				*e ++ = chd[0][i];
			}
		while (s != e)
		{
			int u = *s++;
			for (int i = 0 ; i < CHILD_NUM ; i ++)
			{
				int &v = chd[u][i];
				if (v)
				{
					*e ++ = v;
					fail[v] = chd[fail[u]][i];
					//以下一行代码要根据题目所给val的含义来写
					val[v] |= val[fail[v]];
				}
				else v = chd[fail[u]][i];
			}
		}
	}
	//解题,特定题目需要
	int Work(int n,int m,int k)
	{
		memset(dp[0] , 0 , sizeof(dp[0]));
		dp[0][0][0] = 1;
		int S = 0;
		while (n --)
		{
			int T = 1 - S;
			memset(dp[T] , 0 , sizeof(dp[T]));
			for (int i = 0 ; i < sz ; i ++)
				for (int j = 0 ; j < m ; j ++)
					if (dp[S][i][j])
						for (int k = 0 ; k < CHILD_NUM ; k ++)
						{
							int p = chd[i][k];
							int st = (j | val[p]);
							dp[T][p][st] += dp[S][i][j];
							if (dp[T][p][st] >= mod)
								dp[T][p][st] -= mod;
						}
			S = T;
		}
		int ret = 0;
		for (int j = 0 ; j < m; j ++)
		{
			int cnt = 0;
			int a = j;
			for ( ; a ; cnt += (a&1) , a >>= 1);
			if (cnt < k) continue;
			for (int i = 0 ; i < sz ; i ++)
			{
				ret += dp[S][i][j];
				if (ret >= mod)
					ret -= mod;
			}
		}
		return ret;
	}
}AC;
 
int main()
{
	AC.Initialize();
	int n,m,k;
	while (~scanf("%d%d%d",&n,&m,&k))
	{
		if (n == 0 && m == 0 && k == 0) break;
		AC.Reset();
		for (int i = 0 ; i < m ; i ++) {
			char temp[11];
			scanf("%s",temp);
			AC.Insert(temp , 1 << i);
		}
		AC.Construct();
		printf("%d\n",AC.Work(n , 1 << m , k));
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/frocean/article/details/80840432