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

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

2012-08-08 20:16 309 查看
题意:给出m个致病DNA片段,求长为n且不含致病片段的DNA序列共有多少种。

数据范围:0 <= m <= 10,1 <= n <=2000000000

这题初看起来与上一题差不多,但一看数据范围就傻了……

分析:先建m个致病DNA片段的自动机,然后求出自动机中结点之间转移的路径数目,这样就可以得到一个有向图,所求问题就变为从根结点出发,到达任意一点,所走路径长度为n且路径不经过危险结点的路径数目。再抽象一下,就是求一个边长均为1的有向图中2点之间长为n的路径数目,这就不难想到矩阵了。设G为邻接矩阵,则Gk中第i行j列的元素表示从i到j长为k的路径数目。

View Code

#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
#define M 11
#define LEN 15
#define SIZE (M*LEN)
#define mod 100000

typedef __int64 LL;

int next[M*LEN][4];
int fail[M*LEN];
bool isend[M*LEN];
int m,n,node;
LL mat[M*LEN][M*LEN];
LL tmp[M*LEN][M*LEN];
LL ans[M*LEN][M*LEN];
void init()
{
node=1;
memset(next[0],0,sizeof(next[0]));
}
void add(int cur,int k)
{
memset(next[node],0,sizeof(next[node]));
isend[node]=0;
next[cur][k]=node++;
}
int hash(char c)
{
switch(c)
{
case 'A':   return 0;
case 'C':   return 1;
case 'T':   return 2;
case 'G':   return 3;
}
}
void insert(char *s)
{
int i,k,cur;
for(i=cur=0;s[i];i++)
{
k=hash(s[i]);
if(!next[cur][k])   add(cur,k);
cur=next[cur][k];
}
isend[cur]=1;
}
void build_ac()
{
queue<int>q;
int cur,nxt,tmp;

fail[0]=0;
q.push(0);

while(!q.empty())
{
cur=q.front(),q.pop();
for(int k=0;k<4;k++)
{
nxt=next[cur][k];
if(nxt)
{
if(cur==0)  fail[nxt]=0;
else
{
for(tmp=fail[cur];tmp && !next[tmp][k];tmp=next[tmp][k]);
fail[nxt]=next[tmp][k];
}
if(isend[fail[nxt]]) isend[nxt]=1;
q.push(nxt);
}
else
{
next[cur][k]=next[fail[cur]][k];
}
}
}
}
void build_mat()
{
int cur,nxt,k;
memset(mat,0,sizeof(mat));
for(cur=0;cur<node;cur++)
{
if(isend[cur])  continue;
for(k=0;k<4;k++)
{
nxt=next[cur][k];
if(!isend[nxt])  mat[cur][nxt]++;
}
}
}
void mat_mul(LL a[][SIZE],LL b[][SIZE])
{
for(int i=0;i<node;i++)
{
for(int j=0;j<node;j++)
{
tmp[i][j]=0;
for(int k=0;k<node;k++)
{
tmp[i][j]+=a[i][k]*b[k][j];
}
tmp[i][j]%=mod;
}
}
}
void mat_pow(int k)
{
memset(ans,0,sizeof(ans));
for(int i=0;i<node;i++) ans[i][i]=1;
while(k)
{
if(k&1)
{
mat_mul(ans,mat);
memcpy(ans,tmp,sizeof(tmp));
}
k>>=1;
mat_mul(mat,mat);
memcpy(mat,tmp,sizeof(tmp));
}
}
void solve()
{
build_ac();
build_mat();
mat_pow(n);
LL ret=0;
for(int i=0;i<node;i++) ret+=ans[0][i];
printf("%I64d\n",ret%mod);
}
int main()
{
char s[LEN];
while(~scanf("%d%d",&m,&n))
{
init();
for(int i=0;i<m;i++)
{
scanf("%s",s);
insert(s);
}
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: