刚开始学习AC自动机,碰到这道题,揣摩了好一会儿才弄清楚题解的意思orz
题目要求找出由A,C,T,G构成的长度为n,且不包含给出的子串的字符串数量。
先建trie树。发现如果对符合题意答案串进行AC自动机处理,处理过程中的指针一定不会碰到给出的子串的末节点。所以只要考虑指针在匹配过程中,在trie树上正确地跳来跳去的方案数。用一个矩阵mat[i][j],记下从i节点转移一次到达j节点的方案数。
使不能到达的节点,即给出的子串的末节点不统计进mat矩阵。那么最终答案就是mat矩阵的n方。
有一些重要的细节,
root的fail要指向root自己
无效的next要指向root
#include<cstdio>
#include<queue>
#include<cstring>
#define MOD 100000
using namespace std;
char s[15];
int cnt=-1;
int hash(char ch)
{
switch(ch)
{
case 'A': return 0;
case 'C': return 1;
case 'T': return 2;
case 'G': return 3;
}
return 233;
}
struct matrix
{
long long mat[105][105];
matrix(){memset(mat,0,sizeof(mat));}
matrix operator * (matrix x)
{
matrix r;
for(int i = 0; i <= cnt; i++)
for(int j = 0; j <= cnt; j++)
for(int k = 0; k <= cnt; k++)
r.mat[i][j]=(r.mat[i][j]+mat[i][k]*x.mat[k][j])%MOD;
return r;
}
}mat,matt;
struct node
{
node *fail, *next[5];
bool flag;
int id;
node()
{
fail=NULL;
memset(next,NULL,sizeof(next));
flag=0;
id=++cnt;
}
};
struct ACAutomaton
{
node *root, *id[105];
void init()
{
root=new node;
id[0]=root;
}
void insert(char *s)
{
node *p=root;
for(int i = 0; s[i]; i++)
{
int c=hash(s[i]);
if(p->next[c]==NULL)
{
p->next[c]=new node;
id[cnt]=p->next[c];
}
p=p->next[c];
}
p->flag=true;
}
void build()
{
queue<node*> q;
for(int i = 0; i < 4; i++)
{
if(root->next[i])
{
q.push(root->next[i]);
root->next[i]->fail=root;
}
else
root->next[i]=root;
}
while(!q.empty())
{
root->fail=root;
node *u = q.front();
q.pop();
for(int i = 0; i < 4; i++)
{
if(u->next[i])
{
q.push(u->next[i]);
node *t=u->fail;
while(t!=root && t->next[i]==NULL)
t=t->fail;
if(t->next[i])
{
u->next[i]->flag |= t->next[i]->flag;
u->next[i]->fail = t->next[i];
}
else u->next[i]->fail=root;
}
else u->next[i]=u->fail->next[i];
}
}
}
void matrix()
{
for(int i = 0; i <= cnt; i++)
{
node *u=id[i];
if(u->flag)continue;
for(int j = 0; j < 4; j++)
{
if(u->next[j]==NULL || u->next[j]->flag)continue;
mat.mat[i][u->next[j]->id]++;
}
}
}
}AC;
void matrix_power(int n)
{
for(int i = 0; i <= cnt; i++)
matt.mat[i][i]=1;
for(;n;n>>=1)
{
if(n&1)
matt=matt*mat;
mat=mat*mat;
}
}
int main()
{
int m, n;
scanf("%d%d",&m,&n);
AC.init();
for(int i = 1; i <= m; i++)
{
scanf("%s",s);
AC.insert(s);
}
AC.build();
AC.matrix();
matrix_power(n);
int ans=0;
for(int i = 0; i <= cnt; i++)
{
ans+=matt.mat[0][i];
ans%=MOD;
}
printf("%d\n",ans);
return 0;
}