POJ 题目2778 DNA Sequence(AC自动机,矩阵快速幂)

DNA Sequence
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 13040 Accepted: 4964

Description

It's well known that DNA Sequence is a sequence only contains A, C, T and G, and it's very useful to analyze a segment of DNA Sequence,For example, if a animal's DNA sequence contains segment ATC then it may mean that the animal may have a genetic disease. Until now scientists have found several those segments, the problem is how many kinds of DNA sequences of a species don't contain those segments.

Suppose that DNA sequences of a species is a sequence that consist of A, C, T and G,and the length of sequences is a given integer n.

Input

First line contains two integer m (0 <= m <= 10), n (1 <= n <=2000000000). Here, m is the number of genetic disease segment, and n is the length of sequences.

Next m lines each line contain a DNA genetic disease segment, and length of these segments is not larger than 10.

Output

An integer, the number of DNA sequences, mod 100000.

Sample Input

4 3
AT
AC
AG
AA

Sample Output

36

Source

POJ Monthly--2006.03.26,dodo

题目大意:长度为n不出现这些子串的个数。。

build_ac()的时候略有不同,

具体讲解,http://blog.csdn.net/acm_cxlove/article/details/7854526 

看了好多代码,都不是很一样,看别人解析看了好久还是有些不大懂,主要是build_acde时候,找了一个和我写ac自动机比较像的大牛,按人家代码写了一下,先收藏一下吧

ac代码

#include<stdio.h>
#include<string.h>
#define mod 100000
char key[15];
int head,tail,cnt=0;  
struct node  
{  
    node *fail;  
    node *next[4];  
    int isword,kind;  
}*q[500050],s[500050];
node *newnode()
{
	node *temp=&s[cnt];  
        temp->fail=NULL;  
        temp->kind=cnt++;  
        for(int i=0;i<4;i++)  
            temp->next[i]=NULL;
	return temp;
}
node *root;
int id(char c)
{
	if(c=='A')
		return 0;
	else
		if(c=='T')
			return 1;
		if(c=='C')
			return 2;
		return 3;
}
void insert(char *s)  
{  
    int temp,len,i;  
    node *p=root;  
    len=strlen(s);  
    for(i=0;i<len;i++)  
    {  
        temp=id(s[i]);  
        if(p->next[temp]==NULL)  
            p->next[temp]=newnode();  
        p=p->next[temp];  
    }  
    p->isword=1;
}
void build_ac()  
{  
    q[tail++]=root;  
    while(head!=tail)  
    {  
        node *p=q[head++];  
        node *temp=NULL;  
        for(int i=0;i<4;i++)  
        {  
            if(p->next[i]!=NULL)  
            {  
                if(p==root)  
                    p->next[i]->fail=root;  
                else  
                {  
                    temp=p->fail;  
					//  while(temp!=NULL)  
                    //{  
					//  if(temp->next[i]!=NULL)  
					//{  
					p->next[i]->fail=temp->next[i];  
					//  break;  
					//}
					if(p->next[i]->fail->isword)
						p->next[i]->isword=1;
					//temp=temp->fail;  
				}
				q[tail++]=p->next[i];  
			}
			else
			{
				if(p==root)
					p->next[i]=root;
				else
				{
					p->next[i]=p->fail->next[i];
				}
			}
		}
	}  
}  
struct s
{
	__int64 map[110][110];
}mm;
struct s muti(struct s a,struct s b)
{
	struct	s ans;
	int i,j;
	memset(ans.map,0,sizeof(ans.map));
	int k;
	for(i=0;i<cnt;i++)
	{
		for(k=0;k<cnt;k++)
		{
			if(a.map[i][k]!=0)
			{
				for(j=0;j<cnt;j++)
				{
					ans.map[i][j]+=a.map[i][k]*b.map[k][j];
					if(ans.map[i][j]>=mod)
						ans.map[i][j]%=mod;
				}
			}
		}
	}
	return ans;
}
struct s qpow(struct s a,int n)
{
	int i,j,k;
	struct s ans;
//	printf("MMMMMMMM\n");
	memset(ans.map,0,sizeof(ans.map));
	for(i=0;i<cnt;i++)
		ans.map[i][i]=1;
	while(n)
	{
		if(n&1)
			ans=muti(ans,a);
		a=muti(a,a);
		n>>=1;
		
	}
	return ans;
}
int main()
{
	int n,m;
	while(scanf("%d%d",&m,&n)!=EOF)
	{
		int i,j;
		head=tail=0;
		cnt=0;
		root=newnode();
		
		for(i=0;i<m;i++)
		{
			scanf("%s",key);
			insert(key);
		}
		build_ac();
		memset(mm.map,0,sizeof(mm.map));
	//	printf("%d\n",cnt);
		for(i=0;i<cnt;i++)
		{
			for(j=0;j<4;j++)
			{
				node *son=s[i].next[j];
				if(!son->isword&&!s[i].isword)
				{
					mm.map[i][son->kind]++;
				}
			}
		}
		mm=qpow(mm,n);
		__int64 ans=0;
		for(i=0;i<cnt;i++)
		{
		//	for(j=0;j<cnt;j++)
		//	{
				ans+=mm.map[0][i];
				ans%=mod;
		//	}
		}
		printf("%I64d\n",ans);
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值