链接: https://vjudge.net/problem/POJ-2778
总共有101 个节点,可以建一个101*101的矩阵.
a[i][j] 代表 从节点 i 走到 节点 j 的方案数.
每走一步,都会形成一个后缀.就需要这个后缀不能包含给定的串,
且在构造的串中,加上一个字符不能达到给定的串.
如何构造矩阵呢.,
就是从 i 节点,然后加上任意一个字符可以到达的节点 j, 那么就在 a[i][j] 加一, 我们加的字符,到达 j,新形成的字符串不能是给定字符串的结尾,这个判断一下就好了.
0 就是根节点, 加上一个字符,它或许可以走到下面的节点,那就走到 j, 如果下面没有这样的字符,我们就算走到 0 这个节点,重新匹配.
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N = 10000;
int idx[200],cnt;
queue<int>q;
struct Aho_Corasick_Automaton{
int c[N][26],fail[N];
bool vis[N];
void init(){
memset(vis, 0, sizeof vis);
memset(c, 0, sizeof c);
cnt = 0;
}
void ins(char *s){
int len=strlen(s);int now=0;
for(int i=0;i<len;i++){
int v = idx[(int)s[i]];
if(!c[now][v])c[now][v]=++cnt;
now=c[now][v];
}
vis[now] = 1;
}
void build(){
memset(fail, 0, sizeof fail);
for(int i=0;i<4;i++)
if(c[0][i])q.push(c[0][i]);
while(!q.empty()){
int u=q.front();q.pop();
vis[u] |= vis[fail[u]];
for(int i=0;i<4;i++){
if(c[u][i])fail[c[u][i]]=c[fail[u]][i],q.push(c[u][i]);
else c[u][i]=c[fail[u]][i];
}
}
}
}AC;
int n,m;
char p[50];
struct node{
long long a[200][200];
};
node mul(node A, node B){
node C;
for (int i = 0; i <= cnt; ++i)
for(int j = 0; j <= cnt; ++j)
C.a[i][j] = 0;
for (int i = 0; i <= cnt; ++i)
for (int j = 0; j <= cnt; ++j)
for (int k = 0; k <= cnt; ++k)
C.a[i][j] = (C.a[i][j] + 1ll*A.a[i][k] * B.a[k][j]) % 100000;
return C;
}
node pow(node A, int k){
node B;
for (int i = 0; i <= cnt; ++i)
for (int j = 0; j <= cnt; ++j)
B.a[i][j] = 0;
for (int i = 0; i <= cnt; ++i) B.a[i][i] = 1;
while(k){
if (k & 1) B = mul(B,A);
A = mul(A,A);
k >>= 1;
}
return B;
}
int main(){
idx['A'] = 0; idx['C'] = 1; idx['T'] = 2; idx['G'] = 3;
AC.init();
scanf("%d%d",&m,&n);
for (int i = 0; i < m; ++i){
scanf("%s",p);
AC.ins(p);
}
AC.build();
node A;
for (int i = 0; i <= cnt; ++i)
for (int j = 0; j <= cnt; ++j)
A.a[i][j] = 0;
for (int i = 0; i <= cnt; ++i){
if (AC.vis[i]) continue;
for (int j = 0; j < 4; ++j){
if (AC.vis[AC.c[i][j]]) continue;
A.a[i][AC.c[i][j]] ++;
}
}
for (int i = 0; i <= cnt; ++i){
for (int j = 0; j <= cnt; ++j)
printf("%d ",A.a[i][j]);
printf("\n");
}
A = pow(A,n);
long long ans = 0;
for (int i = 0; i <= cnt; ++i)
ans = (ans + A.a[0][i])% 100000;
printf("%lld\n",ans);
return 0;
}