AC自动机构建fail 指针时与 跟 原来匹配时的 AC自动机有改动。。 就是如果 这个节点k没有next[ i ] , 并不是直接跳过 ,而是 由于求转移矩阵的需要 ,顺着 k 的fail 指针 一直找到 有 next[ i ] ,然后把 k点的 next [ i ] 的指针 指向找到的那个 next[ i ] ,这样 就减少了 , 在求转移矩阵的时候, 失配时的跳转。 但这种方式 只适合求转移矩阵,不能用于匹配。。。。。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
// AC 自动机 模版
typedef long long LL;
const int maxK = 4;
const int maxM = 101;
int size = 0 ; // the size of matrix
struct TreeNode
{
TreeNode *next[maxK];
TreeNode *fail;
bool accept;
int count;
int id;
void init(TreeNode *fl, int i)
{
accept = false;
fail = fl;
id = i;
count = 0;
memset(next, 0, sizeof(next));
}
};
//buildHash()
//init(()
//insert()
//finish()
//match(), buildMat()
template<class T>
struct AC
{
TreeNode *root, *nodes[maxM];
TreeNode *queue[maxM];
bool visit[maxM];
int hash[256];
int C;
TreeNode* newNode()
{
TreeNode *res = new TreeNode;
res->init(root, C);
nodes[C++] = res;
size = C;
return res;
}
void init()
{
C = 0;
root = NULL;
root = newNode();
root -> fail = NULL;
hash['A'] = 0;
hash['C'] = 1;
hash['G'] = 2;
hash['T'] = 3;
}
void insert(char str[])
{
TreeNode *current = root;
for (int i = 0; str[i]; i++)
{
if (!current->next[hash[str[i]]])
current->next[hash[str[i]]] = newNode();
// cout << C-1 << " "<<hash[str[i]]<<" "<< str[i]<<endl;
current = current->next[hash[str[i]]];
}
current->accept = true;//be careful of the repetation
current->count++;
}
void finish()//Build Fail
{
int head = 0, tail = 0;
queue[tail++] = root;
while (head != tail)
{
TreeNode *current = queue[head++];
for (int i = 0; i < maxK; i++)
{
if (current->next[i]){
queue[tail++] = current->next[i];
if (current == root)
continue;
for (TreeNode *t = current->fail; t; t = t->fail)
{
if (t->next[i])
{
current->next[i]->fail = t->next[i];
current->next[i]->accept |= t->next[i]->accept;
break;
}
}
}else{
for(TreeNode *t = current->fail;t; t= t->fail){
if(t->next[i]){
current->next[i] = t->next[i];
break;
}
}
}
}
}
}
void buildMat(T mat[maxM][maxM])//all legal
{
for (int i = 0; i < C; i++)
for (int j = 0; j < C; j++)
mat[i][j] = 0;
for (int i = 0; i < C; i++)
{
for (int j = 0; j < maxK; j++)
{
int flag = 1;
for (TreeNode *t = nodes[i]; t; t = t->fail)
{
if (t->accept)
break;
if (t->next[j])
{
flag = 0;
mat[i][t->next[j]->id] += !t->next[j]->accept;
break;
}
}
mat[i][0] += flag;
}
}
}
void buildMat2(T mat[maxM][maxM]){
for(int i= 0;i<C;i++){
for( int j=0 ;j<C;j++){
mat[i][j] = 0;
}
}
for(int i=0;i<C;i++){
for(int j=0;j<maxK;j++){
TreeNode *t = nodes[i];
if(t->accept) break;
if(t->next[j]){
// if( t -> next[j] -> id== 3 )cout <<i<<" "<< j << "***"<<endl;
mat[i][t->next[j]->id] += !t->next[j]->accept;
}else{
mat[i][0] ++;
}
}
}
}
};
// 矩阵快速幂 模版
const int MOD = 100000;
const int maxn = maxM;
struct Mat{
long long mat[maxn][maxn];
} E,g;
void init_E(){
for(int i=0;i<maxn;i++){
E.mat[i][i] = 1;
}
}
Mat operator*(const Mat &a,const Mat &b){
Mat c;
memset(c.mat,0,sizeof(c.mat));
for(int i=0;i<size;i++)
for(int j=0;j<size;j++){
for(int k=0;k<size;k++){
if(a.mat[i][k] && b.mat[k][j])
c.mat[i][j]=(c.mat[i][j]+a.mat[i][k]*b.mat[k][j]) %MOD;
}
}
return c;
}
Mat operator+(const Mat &a ,const Mat &b){
Mat c;
memset(c.mat,0,sizeof(c.mat));
for(int i=0;i<size;i++)
for(int j=0;j<size;j++){
c.mat[i][j]=(a.mat[i][j]+b.mat[i][j])%MOD;
}
return c;
}
Mat operator^(Mat a,int x){
Mat c=E;
for(;x;x>>=1){
if(x&1)
c=c*a;
a=a*a;
}
return c;
}
int m , n ;
char ss[12];
int mat[maxn][maxn];
int main(){
scanf("%d%d",&m,&n);
AC <int>ac;
ac.init();
while(m--){
scanf("%s",ss);
ac.insert(ss);
}
ac.finish();
ac.buildMat2(mat);
Mat m1;
init_E();
for(int i=0;i<size;i++){
for(int j = 0 ;j<size; j++){
m1.mat[i][j] = mat[i][j];
// cout << mat[i][j] <<" ";
}
// cout <<endl;
}
Mat finnal = m1^n;
int ans = 0 ;
for(int i=0;i<size ;i++){
ans += finnal.mat[0][i];
}
if(ans >= MOD)
ans %= MOD;
cout << ans <<endl;
return 0;
}