POJ 2778
主要利用状态之间的转换吧,可以把各个状态之间的转换成矩阵,利用矩阵乘法来找出有多少条路径。题解转自:
http://blog.csdn.net/morgan_xww/article/details/7834801
•题意:有m种DNA序列是有疾病的,问有多少种长度为n的DNA序列不包含任何一种有疾病的DNA序列。(仅含A,T,C,G四个字符)
•样例m=4,n=3,{“AA”,”AT”,”AC”,”AG”}
•答案为36,表示有36种长度为3的序列可以不包含疾病
这个和矩阵有什么关系呢???

•上图是例子{“ACG”,”C”},构建trie图后如图所示,从每个结点出发都有4条边(A,T,C,G)
•从状态0出发走一步有4种走法:
–走A到状态1(安全);
–走C到状态4(危险);
–走T到状态0(安全);
–走G到状态0(安全);
•所以当n=1时,答案就是3
•当n=2时,就是从状态0出发走2步,就形成一个长度为2的字符串,只要路径上没有经过危险结点,有几种走法,那么答案就是几种。依此类推走n步就形成长度为n的字符串。
•建立trie图的邻接矩阵M:
2 1 0 0 1
2 1 1 0 0
1 1 0 1 1
2 1 0 0 1
2 1 0 0 1
M[i,j]表示从结点i到j只走一步有几种走法。
那么M的n次幂就表示从结点i到j走n步有几种走法。
注意:危险结点要去掉,也就是去掉危险结点的行和列。结点3和4是单词结尾所以危险,结点2的fail指针指向4,当匹配”AC”时也就匹配了”C”,所以2也是危险的。
矩阵变成M:
2 1
2 1
计算M[][]的n次幂,然后 Σ(M[0,i]) mod 100000 就是答案。
由于n很大,可以使用二分来计算矩阵的幂
自己写的代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
#include <string.h>
#include <queue>
#include <cmath>
#include <vector>
#define LL __int64
using namespace std;
const int dictsize=4;
const int QN=1000;
const int root=0;
const LL MOD=100000;
int ID[130];
int head,tail;
int que[QN];
struct Node {
int fail,next[dictsize];
bool tag;
void initial(){
fail=-1,tag=false;
for(int i=0;i<dictsize;i++) next[i]=-1;
}
}trie[150];
int tot,n,l;
char str[15];
struct Matrix{
LL mat[105][105];
};
Matrix a,per;
Matrix operator *(Matrix a,Matrix b){
Matrix c;
for(int i=0;i<=tot;i++){
for(int j=0;j<=tot;j++){
c.mat[i][j]=0;
for(int k=0;k<=tot;k++)
c.mat[i][j]=(c.mat[i][j]+a.mat[i][k]*b.mat[k][j])%MOD;
}
}
return c;
}
void Insert_trie(){
int p=0,i=0;
while(str[i]){
if(trie[p].next[ID[str[i]]]==-1) trie[p].next[ID[str[i]]]=++tot;
p=trie[p].next[ID[str[i]]];
i++;
}
trie[p].tag=true;
}
void build_ac(){
que[tail++]=root;
int i,tmp,p;
while(head!=tail){
tmp=que[head++];
p=-1;
for(int i=0;i<dictsize;i++){
if(trie[tmp].next[i]!=-1){
if(tmp==root) trie[trie[tmp].next[i]].fail=root;
else{
p=trie[tmp].fail;
while(p!=-1){
if(trie[p].next[i]!=-1){
trie[trie[tmp].next[i]].fail=trie[p].next[i];
break;
}
p=trie[p].fail;
}
if(p==-1){
trie[trie[tmp].next[i]].fail=root;
}
}
if(trie[trie[trie[tmp].next[i]].fail].tag){
trie[trie[tmp].next[i]].tag=true;
}
que[tail++]=trie[tmp].next[i];
}
else{ //trie[tmp].next[i]==-1
if(tmp==root) trie[tmp].next[i]=root;
else{
p=trie[tmp].fail;
while(p!=-1){
if(trie[p].next[i]!=-1){
trie[tmp].next[i]=trie[p].next[i];
break;
}
p=trie[p].fail;
}
if(p==-1){
trie[tmp].next[i]=root;
}
}
}
}
}
}
void build_map(){
memset(a.mat,0,sizeof(a.mat));
for(int i=0;i<=tot;i++){
for(int j=0;j<dictsize;j++){
if(!trie[i].tag&&!trie[trie[i].next[j]].tag)
a.mat[i][trie[i].next[j]]++;
}
}
}
Matrix multi(int k){
Matrix ans,p=a;
memset(ans.mat,0,sizeof(ans.mat));
for(int i=0;i<=tot;i++)
ans.mat[i][i]=1;
while(k){
if(k&1) ans=ans*p;
k>>=1;
p=p*p;
}
return ans;
}
int main(){
ID['A']=0,ID['G']=1,ID['C']=2,ID['T']=3;
while(scanf("%d%d",&n,&l)!=EOF){
tot=head=tail=0;
for(int i=0;i<110;i++)
trie[i].initial();
for(int i=0;i<n;i++){
scanf("%s",str);
Insert_trie();
}
build_ac();
build_map();
Matrix ans=multi(l);
LL print=0;
for(int i=0;i<=tot;i++)
print=(print+ans.mat[0][i])%MOD;
printf("%I64d\n",print);
}
return 0;
}

浙公网安备 33010602011771号