zoukankan      html  css  js  c++  java
  • POJ2778 DNA Sequence AC自动机 矩阵

    欢迎访问~原文出处——博客园-zhouzhendong

    去博客园看该题解


    题目传送门 - POJ2778


    题意概括

      现在有一个长度为n(n<=2000000000)的DNA串,其中只可能有A、C、G、T四种字母。现在给出m(m<=10)个危险串(len<=10),求有几种可行的安全串。最终的答案mod 100000。


    题解

      我们先按照输入的危险串构建AC自动机。

      对于当前串在AC自动机上的某一个状态k,我们接下来填一个字母,会有4种不同的转移。

      会转移到其它的不同状态。

      但是不管是从病毒串出发还是到达,都不能涉及,所以,与病毒串相关的转移都要舍去。

      于是我们发下对于每一个状态,每次添加一个字母,所影响的下一个状态是一定的。

      或者说对于某一个状态的总答案,一定是一个固定的由之前递推而来的递推式。

      具体可以参考代码。

      然后我们发现可以用矩阵快速幂优化。

      最后的答案就是从AC自动机虚点转移到其他所有节点(包括虚点)的方案总数。


    代码

    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
    using namespace std;
    typedef long long LL;
    const int MatSize=105,L=15,mod=100000;
    int n,m,s,cnt,Turn[150];
    char ch[L];
    struct Trie{
    	int e,fail,Next[4];
    	void init(){
    		e=fail=0;
    		memset(Next,0,sizeof Next);
    	}
    }tree[MatSize];
    void AC_init(){
    	cnt=1;
    	tree[0].init();
    	tree[1].init();
    	for (int i=0;i<4;i++)
    		tree[0].Next[i]=1;
    }
    void build(char ch[]){
    	int rt=1,t,len=strlen(ch);
    	for (int i=0;i<len;i++){
    		t=Turn[ch[i]];
    		if (!tree[rt].Next[t])
    			tree[tree[rt].Next[t]=++cnt].init();
    		rt=tree[rt].Next[t];
    	}
    	tree[rt].e=1;
    }
    int q[MatSize],head,tail;
    void build_AC(){
    	int rt,k,son;
    	head=tail=0;
    	tree[0].fail=1,tree[1].fail=0;
    	q[++tail]=1;
    	while (head<tail){
    		rt=q[++head];
    		for (int i=0;i<4;i++){
    			son=tree[rt].Next[i];
    			if (!son){
    				tree[rt].Next[i]=tree[tree[rt].fail].Next[i];
    				continue;
    			}
    			k=tree[rt].fail;
    			while (!tree[k].Next[i])
    				k=tree[k].fail;
    			tree[son].fail=tree[k].Next[i];
    			tree[son].e|=tree[tree[k].Next[i]].e;
    			q[++tail]=son;
    		}
    	}
    }
    struct Mat{
    	LL v[MatSize][MatSize];
    	Mat (){}
    	Mat (int x){
    		(*this).set(x);
    	}
    	void set(int x){
    		memset(v,0,sizeof v);
    		if (x==0)
    			return;
    		for (int i=1;i<=s;i++)
    			v[i][i]=1;
    	}
    	Mat operator * (Mat a){
    		Mat ans(0);
    		for (int i=1;i<=s;i++)
    			for (int j=1;j<=s;j++)
    				for (int k=1;k<=s;k++)
    					ans.v[i][j]=(ans.v[i][j]+v[i][k]*a.v[k][j])%mod;
    		return ans;
    	}
    	void operator *= (Mat a){
    		(*this)=(*this)*a;
    	}
    }M,Mans;
    Mat MatPow(Mat x,int y){
    	Mat ans(1),now=x;
    	while (y){
    		if (y&1)
    			ans*=now;
    		now*=now;
    		y>>=1;
    	}
    	return ans;
    }
    int main(){
    	memset(Turn,-1,sizeof -1);
    	Turn['A']=0,Turn['C']=1,Turn['G']=2,Turn['T']=3;
    	scanf("%d%d",&m,&n);
    	AC_init();
    	for (int i=1;i<=m;i++){
    		scanf("%s",ch);
    		build(ch);
    	}
    	build_AC();
    	s=cnt;
    	M.set(0);
    	for (int i=1;i<=s;i++)
    		for (int j=0;j<4;j++){
    			int rt=i,son=tree[i].Next[j];
    			if (!tree[rt].e&&!tree[son].e)
    				M.v[rt][son]++;
    		}
    	Mans=MatPow(M,n);
    	LL ans=0;
    	for (int i=1;i<=s;i++)
    		ans=(ans+Mans.v[1][i])%mod;
    	printf("%lld",ans);
    	return 0;
    }
    

      

  • 相关阅读:
    算法70----只有两个键的键盘【动态规划】
    Shell
    Shell
    Shell
    Shell
    Shell
    Tools
    Jenkins
    Java
    Product
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/POJ2778.html
Copyright © 2011-2022 走看看