您的位置:首页 > 产品设计 > UI/UE

POJ 2778 DNA Sequence(AC自动机+矩阵快速幂+dp)

2018-02-20 10:02 375 查看
DNA Sequence

Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 18472 Accepted: 7109
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

        大致题意,与之前那道题目差不多,也是由指定的一些字母构成的字符串,不能够包换一些不合法的字符,再告诉你一个长度,问你一共有多少个合法的字符串。但不同的是,这道题目的长度可以很长。

        上一道题目,我们介绍了用dp的方法去解决,但是这题面对这么长的长度,显然是不可取的。但是我们回顾一下上一道题目dp的过程,dp[i][j]表示到达AC自动机上的j点走了i步时的方案数,最后要求的是 Σdp
[j],即到达每个合法点走了n步时的方案数总和。而在图论中,邻接矩阵的乘法、次方,恰好可以表示一个人在图中走了确定的某个步数之后的方案数。所以说对于这题,我们可以把AC自动机想象成一个有向图,然后在这个有向图上面走长度那么多的步数。AC自动机上的连边就是这个有向图中的连边,然后对于那些不合法单词,我们还是一样把末尾节点特殊标记为不可达,因为根据AC自动机的性质,能够到达这个点就一定能够构成至少一个不合法单词。构造出矩阵之后,直接矩阵快速幂即可。

        具体见代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
#define INF 0x3f3f3f3f
#define LL long long
#define mod 100000
#define N 105

using namespace std;

int h[256],n,m,p;

struct AC_automation
{

struct node{int fail,cnt,ch[4];} T[110];
int tot,root;

void init()
{
tot=root=0;
memset(T,0,sizeof(T));
}

void ins(char* x)
{
int o=root;
for(int k=0;x[k];k++)
{
int c=h[x[k]];
if(!T[o].ch[c]) T[o].ch[c]=++tot;
o=T[o].ch[c];
}
T[o].cnt++;
}

void get_fail()
{
queue<int> q;
q.push(root);
while(!q.empty())
{
int o=q.front();
T[o].cnt=T[o].cnt|T[T[o].fail].cnt;
for(int i=0;i<4;i++)
{
if (!T[o].ch[i])
{
T[o].ch[i]=T[T[o].fail].ch[i];
continue;
}
if (o!=root)
{
int fa=T[o].fail;
while(fa&&!T[fa].ch[i]) fa=T[fa].fail;
T[T[o].ch[i]].fail=T[fa].ch[i];
} else T[T[o].ch[i]].fail=root;
q.push(T[o].ch[i]);
} q.pop();
}
}

} AC;

struct matrix
{
LL a

;
void init(int x){memset(a,0,sizeof(a));}

friend matrix operator *(matrix x,matrix y)
{
matrix ans;
for(int i=0;i<=p;i++)
for(int j=0;j<=p;j++)
{
ans.a[i][j]=0;
for(int k=0;k<=p;k++)
ans.a[i][j]+=x.a[i][k]*y.a[k][j]%mod;
ans.a[i][j]%=mod;
}
return ans;
}

friend matrix operator ^(matrix x,LL y)
{
matrix ans;
if (y==0)
{
memset(ans.a,0,sizeof(ans.a));
for(int i=1;i<=p;i++) ans.a[i][i]=1;
return ans;
} else while ((y&1)==0) y>>=1,x=x*x;
ans=x; y>>=1;
for(;y!=0;y>>=1)
{
x=x*x; if ((y&1)!=0) ans=ans*x;
}
return ans;
}
} x;

int main()
{
h['A']=0;h['T']=1;
h['C']=2;h['G']=3;
while(~scanf("%d%d",&n,&m))
{
AC.init();char s[15];
for(int i=1;i<=n;i++)
{
scanf("%s",s); AC.ins(s);
}
p=AC.to
1062e
t;
AC.get_fail();
x.init(AC.tot);
for(int i=0;i<=AC.tot;i++)
if (!AC.T[i].cnt)
for(int j=0;j<4;j++)
{
int k=AC.T[i].ch[j];
if (!AC.T[k].cnt) x.a[i][k]++;
}
x=x^m; int ans=0;
for(int i=0;i<=AC.tot;i++)
ans=(ans+x.a[0][i])%mod;
cout<<ans<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: