码迷,mamicode.com
首页 > 其他好文 > 详细

poj 2778 AC自动机 + 矩阵快速幂

时间:2015-08-06 22:32:21      阅读:183      评论:0      收藏:0      [点我收藏+]

标签: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;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

poj 2778 AC自动机 + 矩阵快速幂

标签:poj 2778   ac自动机   矩阵快速幂   

原文地址:http://blog.csdn.net/timelimite/article/details/47322659

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!