题目:http://poj.org/problem?id=2778
题意:给出N段DNA序列(仅由‘A’,'T','G','C'四种字符组成),求一段长为L的DNA序列不包含前面给出的任何DNA序列的方案数。
分析:将N个字符串建成ac自动机,然后把所有禁止走的位置标记出来,然后利用ac自动机建二维矩阵Matrix[][],Matrix[u][v]表示节点u走一步到节点v的路径数。然后利用矩阵快速幂求出方案数。
PS:这题就是ac自动机建图+hdu 5318。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
typedef long long LL;
const int maxn = 103;
const int kd = 4;
const LL mod = 100000 ;
int Msz;
struct Matrix
{
LL M[maxn][maxn];
}U,P;
Matrix Multi(const Matrix &a,const Matrix &b)
{
Matrix ret;
memset(ret.M,0,sizeof(ret.M));
for(int i=0;i<Msz;i++)
for(int j=0;j<Msz;j++)
{
for(int k=0;k<Msz;k++)
ret.M[i][j]+=a.M[i][k]*b.M[k][j];
ret.M[i][j]%=mod;
}
return ret;
}
Matrix Pow(Matrix a,int n)
{
Matrix ret=U;
while(n)
{
if(n&1)
ret=Multi(ret,a);
a=Multi(a,a);
n>>=1;
}
return ret;
}
struct trie
{
int son[maxn][kd],fbd[maxn],fail[maxn];
int cnt,root;
int newnode()
{
fill(son[cnt],son[cnt]+kd,-1);
fbd[cnt]=0;
return cnt++;
}
void Init()
{
cnt=0;
root=newnode();
}
inline int idx(char ch)
{
switch(ch)
{
case 'A' : return 0;
case 'C' : return 1;
case 'G' : return 2;
case 'T' : return 3;
}
return -1;
}
void Insert(char str[])
{
int index,i,now=root;
for(i=0;str[i];i++)
{
index=idx(str[i]);
if(son[now][index]==-1)
son[now][index]=newnode();
now=son[now][index];
}
fbd[now]=1;
}
void findfail()
{
queue <int > q;
int temp,i;
for(i=0;i<kd;i++)
if(son[root][i]==-1)
son[root][i]=root;
else
{
fail[son[root][i]]=root;
q.push(son[root][i]);
}
while(!q.empty())
{
temp=q.front();
q.pop();
fbd[temp]|=fbd[fail[temp]];
for(i=0;i<kd;i++)
if(son[temp][i]==-1)
son[temp][i]=son[fail[temp]][i];
else
{
fail[son[temp][i]]=son[fail[temp]][i];
q.push(son[temp][i]);
}
}
}
void GetU()
{
for(int i=0;i<maxn;i++)
U.M[i][i]=1;
}
int Next(int cur,int x)
{
if(fbd[cur] || fbd[son[cur][x]])
return -1;
return son[cur][x];
}
void GetP()
{
Msz=cnt;
memset(P.M,0,sizeof(P.M));
for(int i=0;i<Msz;i++)
{
for(int j=0;j<kd;j++)
{
int temp=Next(i,j);
if(temp==-1)
continue ;
++P.M[i][temp];
}
}
}
}ac;
char ss[maxn];
int main()
{
int n,m,i,j;
LL N,ans;
ac.GetU();
while(scanf("%d%lld",&n,&N)!=EOF)
{
ac.Init();
while(n--)
{
scanf("%s",ss);
ac.Insert(ss);
}
ac.findfail();
ac.GetP();
ans=0;
if(N==1)
{
for(i=0;i<kd;i++)
ans+=P.M[ac.root][i];
}
else
{
Matrix temp=Pow(P,N-1);
int buf[maxn]={0};
for(i=0;i<kd;i++)
{
int temp=ac.Next(ac.root,i);
if(temp==-1)
continue ;
buf[temp]++;
}
for(i=0;i<Msz;i++)
for(j=0;j<Msz;j++)
ans+=buf[j]*temp.M[j][i]%mod;
}
printf("%lld\n",ans%mod);
}
return 0;
}