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

AC自动机构建fail 指针时与 跟 原来匹配时的 AC自动机有改动。。 就是如果    这个节点k没有next[ i ] , 并不是直接跳过 ,而是 由于求转移矩阵的需要 ,顺着 k 的fail 指针 一直找到 有 next[ i ] ,然后把 k点的 next [ i ] 的指针 指向找到的那个 next[ i ] ,这样 就减少了 , 在求转移矩阵的时候, 失配时的跳转。 但这种方式 只适合求转移矩阵,不能用于匹配。。。。。



#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

// AC 自动机 模版
typedef long long LL;
const int maxK = 4;
const int maxM = 101;
int size = 0 ; // the size of matrix
struct TreeNode
{
	TreeNode *next[maxK];
	TreeNode *fail;
	bool accept;
	int count;
	int id;
	void init(TreeNode *fl, int i)
	{
		accept = false;
		fail = fl;
		id = i;
		count = 0;
		memset(next, 0, sizeof(next));
	}
};

//buildHash()
//init(()
//insert()
//finish()
//match(), buildMat()

template<class T>
struct AC
{
	TreeNode *root, *nodes[maxM];
	TreeNode *queue[maxM];
	bool visit[maxM];
	int hash[256];
	int C;
	TreeNode* newNode()
	{
		TreeNode *res = new TreeNode;
		res->init(root, C);
		nodes[C++] = res;
		size = C;
		return res;
	}
	void init()
	{
		C = 0;
		root = NULL;
		root = newNode();
		root -> fail = NULL;
		hash['A'] = 0;
		hash['C'] = 1;
		hash['G'] = 2;
		hash['T'] = 3;
	}
	void insert(char str[])
	{
		TreeNode *current = root;
		for (int i = 0; str[i]; i++)
		{
			if (!current->next[hash[str[i]]])
				current->next[hash[str[i]]] = newNode();
	//		cout << C-1 << " "<<hash[str[i]]<<"  "<< str[i]<<endl;
			current = current->next[hash[str[i]]];
		}
		current->accept = true;//be careful of the repetation
		current->count++;
	}
	void finish()//Build Fail
	{
		int head = 0, tail = 0;
		queue[tail++] = root;
		while (head != tail)
		{
			TreeNode *current = queue[head++];
			for (int i = 0; i < maxK; i++)
			{
				if (current->next[i]){
				  queue[tail++] = current->next[i];
				  if (current == root)
					continue;
				  for (TreeNode *t = current->fail; t; t = t->fail)
				  { 
					if (t->next[i])
					{
						current->next[i]->fail = t->next[i];
						current->next[i]->accept |= t->next[i]->accept;
						break;
					}
				  }
				}else{
				  for(TreeNode *t = current->fail;t; t= t->fail){
				      if(t->next[i]){
				         current->next[i] = t->next[i];
					 break;
				      }   
				  }
				}
			}
		}
	}
	void buildMat(T mat[maxM][maxM])//all legal
	{
		for (int i = 0; i < C; i++)
			for (int j = 0; j < C; j++)
				mat[i][j] = 0;
		for (int i = 0; i < C; i++)
		{
			for (int j = 0; j < maxK; j++)
			{
				int flag = 1;
				for (TreeNode *t = nodes[i]; t; t = t->fail)
				{
					if (t->accept)
						break;
					if (t->next[j])
					{
						flag = 0;
						mat[i][t->next[j]->id] += !t->next[j]->accept;
						break;
					}
				}
				mat[i][0] += flag;
			}
		}
	}
        void  buildMat2(T mat[maxM][maxM]){
	   for(int i= 0;i<C;i++){
	     for( int j=0 ;j<C;j++){
	         mat[i][j] = 0;
	     }
	   }
          for(int i=0;i<C;i++){
	     for(int j=0;j<maxK;j++){
	            TreeNode *t  = nodes[i];
                    
		    if(t->accept) break;
		    if(t->next[j]){
	//		    if( t -> next[j] -> id== 3 )cout <<i<<"  "<< j << "***"<<endl; 
		       mat[i][t->next[j]->id] += !t->next[j]->accept;
		    }else{
		       mat[i][0] ++;
		    }
	     }
	  }
	}
};
//  矩阵快速幂 模版
 const int  MOD = 100000;
const int maxn = maxM;
struct Mat{
	long long mat[maxn][maxn];
} E,g;
void init_E(){
   for(int i=0;i<maxn;i++){
        E.mat[i][i] = 1;
     
   }
}
Mat operator*(const Mat &a,const Mat &b){
	Mat c;
	memset(c.mat,0,sizeof(c.mat));
	for(int i=0;i<size;i++)
		for(int j=0;j<size;j++){
			for(int k=0;k<size;k++){
				if(a.mat[i][k] && b.mat[k][j])
					c.mat[i][j]=(c.mat[i][j]+a.mat[i][k]*b.mat[k][j]) %MOD;
			}
		}
	return c;
}
Mat operator+(const Mat &a ,const Mat &b){
	Mat c;
	memset(c.mat,0,sizeof(c.mat));
	for(int i=0;i<size;i++)
		for(int j=0;j<size;j++){
			c.mat[i][j]=(a.mat[i][j]+b.mat[i][j])%MOD;
		}
	return c;
}
Mat operator^(Mat a,int x){
	Mat c=E;
	for(;x;x>>=1){
		if(x&1)
			c=c*a;
		a=a*a;
	}
	return c;
}
int m , n ;
char ss[12];
int mat[maxn][maxn];
int main(){
   scanf("%d%d",&m,&n);
   AC <int>ac;
   ac.init();
   while(m--){
      scanf("%s",ss);
      ac.insert(ss);
   }
   ac.finish();
   ac.buildMat2(mat);
   Mat m1;
   init_E();
   for(int  i=0;i<size;i++){
     for(int j = 0 ;j<size; j++){
       m1.mat[i][j]  = mat[i][j];
   //    cout << mat[i][j] <<" ";
     }
  //   cout <<endl;
   }
    Mat finnal = m1^n;
   int  ans = 0 ;
   for(int i=0;i<size ;i++){
      ans += finnal.mat[0][i];
   }
   if(ans >= MOD)
	   ans %= MOD;
   cout << ans <<endl;
  
  return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值