zoukankan      html  css  js  c++  java
  • 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;
    }
    

  • 相关阅读:
    【MyBatis】MyBatis实现CRUD操作
    【MyBatis】 MyBatis入门
    【MySQL】MySQL数据库再安装
    我的大数据学习历程
    汇编语言——指令系统
    大数据概论
    Python云端系统开发入门——框架基础
    Perl碎碎念
    Oracle函数之LISTAGG
    如何利用Oracle外部表导入文本文件的数据
  • 原文地址:https://www.cnblogs.com/gccbuaa/p/7284442.html
Copyright © 2011-2022 走看看