poj 2778 AC自己主动机 + 矩阵高速幂

//	poj 2778 AC自己主动机 + 矩阵高速幂
//
//	题目链接:
//		
//		http://poj.org/problem?id=2778
//
//	解题思路:
//
//		建立AC自己主动机,确定状态之间的关系,构造出,走一步
//	能到达的状态矩阵,然后进行n次乘法,就能够得到状态间
//	走n步的方法数.
//	精髓:
//		1):这个ac自己主动机有一些特别,根节点是为空串,然而
//	每走一步的时候,假设没法走了,这时候,不一定是回到根
//	节点,由于有可能单个的字符时病毒,这样,不是随便就能达到
//	所谓的根节点的,所以每次初始化的时候,不能是0,而应该是
//	-1.
//
//	感悟:
//
//		这道AC自己主动机,開始我是全然不会,知道是AC自己主动机+矩阵高速幂
//	開始,自以为AC自己主动机构造的非常对,并且例子都过了好嘛,结果一直是
//	wrong answer.我就不信邪了,肯定是博主博客有错误,我就将博主的
//	交了一发,然而,博主的过了,我的没过.哎,一阵伤心,但心里也是再次
//	燃起了希望之火,还是能够搞得.然而我就细致研究,对拍呗,自己造了
//	几个例子.发现以下这组:
//		4 2
//		A
//		C
//		T
//		GT
//	这组例子,答案应该是1,而我的答案是3.我仿佛一下子恍然大悟,发现
//	单个字符是病毒,不能走回根节点.明确了过后,一改,就AC了,尽管速度
//	有点慢,可是我发现自己对AC自己主动机的理解又有了一点小小的新的拓展
//	尽管作为菜鸟的我敢于怀疑是一件好事,可是自己的不正确就是不正确,不要
//	由于自己的自信就去刻意寻找别人的错误,觉得别人是错误的.有着一颗
//	敢于承认错误,并且接受正确观念,并明悟的人,我觉得光明,就在前方!
	   

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

typedef long long ll;

const int MAX_NODE = 110;
const ll MOD = 100000;
const int MAX_N = 110;

struct Matrix{
	ll mat[MAX_N][MAX_N];
}res;

int n,m;

struct Aho_Corasick{

	int ch[MAX_NODE][4];

	bool val[MAX_NODE];

	int f[MAX_NODE];
	
	//int last[MAX_NODE];

	int sz;

	void init(){
		memset(ch[0],-1,sizeof(ch[0]));
		val[0] = 0;
		sz = 1;
		f[0] = 0;
		//last[0] = 0;
	}

	int idx(char c){
		if (c == 'A')
			return 0;
		if (c == 'T')
			return 1;
		if (c == 'C')
			return 2;
		return 3;
	}

	void insert(char *s){
		int u = 0;
		int n = strlen(s);
		for (int i=0;i<n;i++){
			int c = idx(s[i]);
			if (ch[u][c]==-1){
				memset(ch[sz],-1,sizeof(ch[sz]));
				val[sz] = 0;
				ch[u][c] = sz++;
			}
			u = ch[u][c];
		}
		val[u] = true;
	}

	void getfail(){
		queue<int> que;
		f[0] = 0;
		for (int c = 0;c < 4;c++){
			int u = ch[0][c];
			if (u!=-1){
				que.push(u);
				f[u] = 0;
			//	last[u] = 0;
			}else{
				ch[0][c] = 0; //表示当此c单个字符不是病毒的时候,则能够走回根
			}
		}

		while(!que.empty()){
			int r = que.front();
			que.pop();

			if (val[f[r]]) // 当r的某个后缀为病毒的时候标记此r
				val[r] = true;

			for (int c = 0; c < 4;c++){
				int u = ch[r][c];
				
				if (u == -1){
					ch[r][c] = ch[f[r]][c]; //把不存在的边接上去
					continue;
				}
				que.push(u);

				int v = f[r];
				while(v && ch[v][c]==-1)
					v = f[v];

				f[u] = ch[v][c];

				//last[u] = val[f[u]] ? f[u] : last[f[u]];
			}
		}
	}

	void get_matrix(){
		
		memset(res.mat,0,sizeof(res.mat));

		for (int u=0;u<sz;u++){
			for (int c = 0;c < 4;c++){
				if (!val[u] && !val[ch[u][c]])
					res.mat[u][ch[u][c]]++;
			}
		}
	}


}ac;

Matrix Mulity(Matrix a,Matrix b){
	Matrix ans;

	for (int i=0;i < ac.sz;i++)
		for (int j=0;j < ac.sz;j++){
			ans.mat[i][j] = 0;
			for (int k=0;k < ac.sz ;k++)
 				ans.mat[i][j] = (ans.mat[i][j] + a.mat[i][k] * b.mat[k][j])%MOD;
			ans.mat[i][j] %= MOD;
		}

	return ans;
}


Matrix Matrix_power(Matrix a,int b){
	Matrix ans;
	memset(ans.mat,0,sizeof(ans.mat));
	for (int i=0;i<ac.sz;i++)
		ans.mat[i][i] = 1;

	while(b){
		if (b & 1)	ans = Mulity(ans,a);
		a = Mulity(a,a);
		b >>=1;
	}
	return ans;
}

void print(Matrix r){
	for (int i=0;i<ac.sz;i++){
		for (int j=0;j<ac.sz;j++)
			cout << r.mat[i][j] << " ";
		cout << endl;
	}
}

void input(){
	ac.init();
	char s[20];
	for (int i=1;i<=m;i++){
		scanf("%s",s);
		ac.insert(s);
	}
	ac.getfail();
	ac.get_matrix();
//	print(res);
	res = Matrix_power(res,n);
//	cout << endl;
//	print(res);
	ll ans = 0;
	
	for (int i=0;i<ac.sz;i++){
		ans = (ans + res.mat[0][i])%MOD;
	}
	cout << ans%MOD << endl;
}



int main(){
	//freopen("1.txt","r",stdin);
	while(scanf("%d%d",&m,&n)!=EOF){
	//	puts("-------");
		input();
	}
	return 0;
}

原文地址:https://www.cnblogs.com/gccbuaa/p/7284442.html