zoukankan      html  css  js  c++  java
  • POJ2778 DNA sequence

    题目大意:给出m个疾病基因片段(m<=10),每个片段不超过10个字符。求长度为n的不包含任何一个疾病基因片段的DNA序列共有多少种?(n<=2000000000)

    分析:本题需要对m个疾病基因片段构建一个AC自动机,自动机中的每个节点表示一个状态。其中AC自动机中的叶子节点表示的是病毒,所以是非法状态。同时,如果某个节点到根的字符串的后缀是一个病毒,那么该节点也是非法状态。剔除掉所有的非法状态,那么剩下的节点都表示合法状态了。然后用节点的nxt指针表示状态之间转化关系。若nxt[i]==0,则nxt[i]指针指向当前节点fail指针的nxt[i],如果仍然为0,则nxt[i]指向根节点。这样处理以后,每个指针都不会指向0。这样,该自动机可以看做是一个合法状态的转换图,节点表示各种合法状态,边表示添加一个字符将转换为另一个状态。于是我们可以得到一个矩阵。该矩阵实际上表示该状态图的邻接矩阵。对该矩阵自乘n次。最后结果矩阵的第1行各元素之和表示从空状态添加n个字符能够得到的所有合法状态的数量。

    矩阵的思想非常巧妙。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define MAXN 102
    #define MAXL 12
    #define MAXC 4
    #define MOD 100000
    struct node
    {
    	int fail,nxt[6],flag;
    }trie[MAXN];
    int head,tail,myq[MAXN],root=1,tot=1;
    char word[MAXL];
    int degree;
    int a[MAXN][MAXN],b[MAXN][MAXN],c[MAXN][MAXN],(*ans)[MAXN];
    void multi(int (*a)[MAXN],int (*b)[MAXN],int (*c)[MAXN])
    {
       for(int i=1;i<=degree;i++)
      {
        for(int j=1;j<=degree;j++)
        c[i][j]=0;
      }
      for(int i=1;i<=degree;i++)
      {
        for(int j=1;j<=degree;j++)
        {
         for(int k=1;k<=degree;k++)
         {
             c[i][j]+=(long long)a[i][k]*b[k][j]%MOD;
             c[i][j]%=MOD;
         }
        }
      }
    }
    void power(int (*t1)[MAXN],int h)
    {
        for(int i=1;i<=degree;i++)
            for(int j=1;j<=degree;j++)
             b[i][j]=0;
        for(int i=1;i<=degree;i++)
              b[i][i]=1;
        int (*t2)[MAXN],(*t3)[MAXN];
        t2=b,t3=c;
        while(h)
        {
           if(h&1)
             {multi(t1,t2,t3);
              swap(t2,t3);
             }
             h>>=1;
             multi(t1,t1,t3);
             swap(t1,t3);
        }
        if(t2!=a)
        {
            memcpy(a,t2,sizeof a);
        }
    }
    int inline getid(char C)
    {
    	if(C=='A')return 0;
    		else if(C=='T')return 1;
    	     else if(C=='C')return 2;
    	else return 3;
    }
    void insert(int r,char *s)
    {
    	int len=strlen(s);
    	for(int i=0;i<len;i++)
    	{
    		int val=getid(s[i]);
    		if(trie[r].nxt[val]==0)
    			trie[r].nxt[val]=++tot;
    		r=trie[r].nxt[val];
    	}
    	trie[r].flag=1;//1表示结束节点
    }
    void build(int r)
    {
    	trie[r].fail=r;
    	myq[tail++]=r;
    	int ch;
    	while(head<tail)
    	{
    	  	r=myq[head++];
    		for(int i=0;i<MAXC;i++)
    		{
    			ch=trie[r].nxt[i];
    			if(ch)myq[tail++]=ch;
    			if(r==root)
    			{
    			    if(ch)
    				trie[ch].fail=root;
    				else trie[r].nxt[i]=root;
    			}
    			else
    			{
    				if(ch)
    				{trie[ch].fail=trie[trie[r].fail].nxt[i];
    				  trie[ch].flag|=trie[trie[ch].fail].flag;
    				}
    				else
    				trie[r].nxt[i]=trie[trie[r].fail].nxt[i];
    			}
    		    ch=trie[r].nxt[i];
    			if(trie[ch].flag!=1)
    				a[r][ch]++;
    		}
    	}
    }
    int main()
    {
    	int n,m;
    	scanf("%d%d",&m,&n);
    	for(int i=0;i<m;i++)
    	{
    		scanf("%s",word);
    		insert(root,word);
    	}
    	build(root);
    	degree=tot;
        power(a,n);
    	int ans=0;
    	for(int i=1;i<=degree;i++)
    	{ans+=a[1][i];
        ans%=MOD;
    	}
    	printf("%d
    ",ans);
    }
    

      

  • 相关阅读:
    接口的经典使用方法
    多态的程序例子
    log4j常用配置过程
    log4j.properties对于web app摆放的位置
    MySQL优化实例
    No sql 相关
    yii直接执行sql
    android NDK JNI设置自己的log输出函数
    android web 网址收集
    WebKit加载网页的流程
  • 原文地址:https://www.cnblogs.com/hefenghhhh/p/5056768.html
Copyright © 2011-2022 走看看