题目链接:http://poj.org/problem?id=2778
题意:只有四种字符的字符串(A, C, T , G),其中给出M种字符串不能出现,问为长度为n的字符串可以有多少种。
思路:我觉得这篇大佬的博客讲的很好:https://blog.csdn.net/morgan_xww/article/details/7834801。
总体思路就是用M个串建一个ac自动机,然后遍历所有trie树上的点i与它能到达的点j,若没找到这样的串,那么i点和j点可达,从i到j的字符串就是符合条件的串,注意:当前结点可能不是一个病毒串的终点,但是其失配边指向的串是个病毒,说明当前串的后缀也是个病毒串。
还有一个重点是矩阵,先建一个邻接矩阵A存走一步即可达的走法有多少,走n步(即找到长度为n的串)为A^n
(复制大佬的解释:把给定的图转为邻接矩阵,即A(i,j)=1当且仅当存在一条边i->j。令C=A*A,那么C(i,j)=ΣA(i,k)*A(k,j),实际上就等于从点i到点j恰好经过2条边的路径数(枚举k为中转点)。类似地,C*A的第i行第j列就表示从i到j经过3条边的路径数。同理,如果要求经过k步的路径数,我们只需要二分求出A^k即可)
注意:这题取模太多会TLE(卡了很久翻discuss才知道0.0)。
代码:
#include <cstdio>
#include <cmath>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <numeric>
#include <set>
#include <string>
#include <cctype>
#include <sstream>
#define INF 0x3f3f3f3f
#define eps 1e-7
#define fuck(x) cout<<"<"<<x<<">"<<endl;
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int maxn = 1e4 + 5;
const int mod = 1e9 + 7;
const int N = 4;
const int MAXN = 105;
const int Mod = 100000;
int m,n;
const int M = 105;
struct Matrix{
LL m[M][M];
};
Matrix mul(Matrix a,Matrix b,int len){
Matrix c;
memset(c.m,0,sizeof(c.m));
for (int i=0;i<len;i++){
for (int j=0;j<len;j++){
for (int k=0;k<len;k++){
c.m[i][j]=(c.m[i][j]+a.m[i][k]*b.m[k][j])%Mod;
}
}
}
return c;
}
Matrix q_mul(Matrix a,int n,int len){
Matrix ans;
memset(ans.m,0,sizeof(ans.m));
for (int i=0;i<len;i++) ans.m[i][i]=1;
while (n){
if (n&1) ans=mul(ans,a,len);
n>>=1;
a=mul(a,a,len);
}
return ans;
}
struct Trie {
int next[MAXN][N], fail[MAXN], end[MAXN];
int root;
int tot;
int idx(char ch){
switch(ch){
case 'A':return 0;
case 'C':return 1;
case 'T':return 2;
case 'G':return 3;
}
return -1;
}
int newnode() {
for(int i = 0; i < N; i++)
next[tot][i] = -1;
end[tot++] = 0;
return tot - 1;
}
void init() {
tot = 0;
root = newnode();
}
void insert(char buf[]) {
int len = strlen(buf);
int now = root;
for(int i = 0; i < len; i++) {
int k = idx(buf[i]);
if(next[now][k] == -1)
next[now][k] = newnode();
now = next[now][k];
}
end[now]=1;
}
void build() {
queue<int> que;
fail[root] = root;
for(int i = 0; i < N; i++)
if(next[root][i] == -1)
next[root][i] = root;
else {
fail[next[root][i]] = root;
que.push(next[root][i]);
}
while(!que.empty()) {
int now = que.front();
que.pop();
if (end[fail[now]]) end[now]=1;
for(int i = 0; i < N; i++)
if(next[now][i] == -1)
next[now][i] = next[fail[now]][i];
else {
fail[next[now][i]] = next[fail[now]][i];
que.push(next[now][i]);
}
}
}
int query(int n) {
Matrix x;
memset(x.m,0,sizeof(x.m));
for (int i=0;i<tot;i++){
for (int j=0;j<N;j++){
int tmp = next[i][j];
if (!end[tmp]) x.m[i][tmp]++;
}
}
x=q_mul(x,n,tot);
int ans=0;
for (int i=0;i<tot;i++){
ans=(ans+x.m[0][i])%Mod;
}
return ans;
}
};
Trie ac;
char buf[15];
int main() {
while (~scanf ("%d%d",&m,&n)) {
ac.init();
for(int i = 0; i < m; i++) {
scanf("%s", buf);
ac.insert(buf);
}
ac.build();
printf("%d\n", ac.query(n));
}
return 0;
}