题目链接:
POJ:http://poj.org/problem?id=2778
SCU:http://acm.scu.edu.cn/soj/problem.action?id=3030(多组输入)
一个是单组,另一个是多组输入。
题意:DNA序列由'A''C''G''T'
四个元素组成。问有多少种长度为n的DNA序列不包含任何一种有疾病的DNA序列。
解题思路:其实这道题在想到矩阵之前还挺难的…
我开始时也很纳闷,怎么这道题和矩阵扯上关系了呢?不急我们慢慢来…
为了完成矩阵M。我们需要对所有的疾病DNA序列构建前缀树。并记录每个病毒结尾时的位置。这时,我们就可以根据前缀树的性质,排除掉M中这些病毒结尾时的位置。
但还有些病毒没有被排除,比如病毒是'ACG'
和'C'
那么'AC'
也要被排除因为AC的fail指向C的。所以我们需要对这棵前缀树求其fail指针。
上述工作做完之后就可以开始求M了。对每一个点,判断是否可以走ACGT这四个方向。
M[0].mat[i][trie[fail[i]][k]]++
。相当于借助失配指针查找可以走到的位置。比如对于3 AC CA G
这组病毒来说,其矩阵M就应该为
1 1 0 1 0 0
1 1 0 0 0 0
0 0 0 0 0 0
1 0 0 1 0 0
0 0 0 0 0 0
0 0 0 0 0 0
现在我们得到了M矩阵,从i到j走一步有多少种方法。下面是我认为最难想到的…
矩阵
没错,Mn就是从i到j走n步有多少种方法…那么我们对M使用矩阵快速幂即可。
最后我们再统计从Mn[0][0]加到Mn[0][tot]就可以了…
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
//#pragma GCC optimize(3,"Ofast","inline")
#define LL long long
#define MT(a,b) memset(a,b,sizeof(a))
const int mod=100000;
const int maxn=2e6+10;
const int ONF=-0x3f3f3f3f;
const int INF=0x3f3f3f3f;
struct node{
LL mat[150][150];
}M[5];
char t[20][20];
int trie[500][30],fail[500],vis[500],tot;
char dir[200];
void add_trie(char *str){
int len=strlen(str);
int pos=0;
for (int i=0;i<len;i++){
if (!trie[pos][dir[str[i]]]) trie[pos][dir[str[i]]]=++tot;
pos=trie[pos][dir[str[i]]];
}
vis[pos]++;
}
void get_fail(){
queue<int>q;
for (int i=0;i<4;i++){
if(trie[0][i]){
q.push(trie[0][i]);
fail[trie[0][i]]=0;
}
}
while (!q.empty()){
int pos=q.front();
q.pop();
for (int i=0;i<4;i++){
if (trie[pos][i]) {
fail[trie[pos][i]]=trie[fail[pos]][i];
if (vis[fail[trie[pos][i]]]) vis[trie[pos][i]]++;
q.push(trie[pos][i]);
} else trie[pos][i]=trie[fail[pos]][i];
}
}
}
void build_trie(int n){
MT(trie,0);
MT(vis,0);
MT(fail,0);
tot=0;
dir['A']=0,dir['C']=1,dir['G']=2,dir['T']=3;
for (int i=0;i<n;i++){
scanf("%s",t[i]);
add_trie(t[i]);
}
get_fail();
for (int i=0;i<=tot;i++){
if (vis[i]) continue;
for (int k=0;k<4;k++){
if (trie[i][k]){
if (!vis[trie[i][k]])
M[0].mat[i][trie[i][k]]++;
} else {
if (trie[0][k]) M[0].mat[i][trie[0][k]]++;
else M[0].mat[i][0]++;
}
}
}
}
void mat_mul(int a,int b,int d){
node tmp = node();
for (int i=0;i<=tot;i++){
for (int j=0;j<=tot;j++){
for (int k=0;k<=tot;k++){
tmp.mat[i][j]+=M[a].mat[i][k]*M[b].mat[k][j];
tmp.mat[i][j]%=mod;
}
}
}
M[d]=tmp;
}
void mat_qpow(int n,int p){
for (int i=0;i<=tot;i++){
M[1].mat[i][i]=1;
}
while (p){
if (p&1){
mat_mul(n,1,1);
}
p>>=1;
mat_mul(n,n,n);
}
}
int main(){
int n,L;
while (~scanf("%d%d",&n,&L)){
MT(M[0].mat,0);
MT(M[1].mat,0);
build_trie(n);
int ans=0;
mat_qpow(0,L);
for (int i=0;i<=tot;i++){
ans+=M[1].mat[0][i];
ans=ans%mod;
}
printf("%d\n",ans);
}
return 0;
}