求长度为n的串中不包含模式串的串的数目
首先将模式串建成AC自动机,将模式串标记,这里需要注意的是,如果一个节点的失败指针也指向了一个模式串,那么该节点也需要被标记。
建好AC自动机后,我们就建立了转化关系,然后我们就可以使用DP的方式计算答案。
考虑到n的范围很大,所以我们将所有不包含模式串的转化关系构建一个矩阵,使用矩阵快速幂求出长度为n的串的方案数,最后累加即可。
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 100 + 10;
const int child_num = 4;
const int mo = 100000;
struct Matrix
{
long long v[maxn][maxn];
int x,y;
Matrix()
{
memset(v,0,sizeof(v));
x = y = 0;
}
}mat;
char tmp[maxn];
int n,m,sz,matnum;
int matcal[maxn];
class ACAutumaton
{
public:
int chd[maxn][child_num];
int fail[maxn],val[maxn];
int Q[maxn],ID[maxn];
int cnt;
void Reset()
{
memset(fail,0,sizeof(fail));
ID['A'] = 0;ID['C'] = 1;
ID['T'] = 2;ID['G'] = 3;
sz = 1;
}
void Insert(char *a,int key)
{
int p = 0;
for(;*a ;a++)
{
int c = ID[*a];
if(!chd[p][c])
{
memset(chd[sz],0,sizeof(chd[sz]));
val[sz] = 0;
chd[p][c] = sz ++;
}
p = chd[p][c];
}
val[p] = key;
}
void Construct()
{
int *s = Q,*e = Q;
for(int i = 0;i < child_num;i++)
{
if(chd[0][i])
{
fail[ chd[0][i] ] = 0;
*e++ = chd[0][i];
}
}
while(s != e)
{
int u = *s++;
for(int i = 0;i < child_num;i++)
{
int &v = chd[u][i];
if(v)
{
*e++ = v;
fail[v] = chd[ fail[u] ][i];
val[v] |= val[fail[v]];
}
else v = chd[ fail[u] ][i];
}
}
}
}AC;
void init()
{
freopen("poj2778.in","r",stdin);
freopen("poj2778.out","w",stdout);
}
void work()
{
memset(matcal,0,sizeof(matcal));
matnum = 0;
for(int i = 0;i < sz;i++)
if(!AC.val[i])matcal[i] = ++matnum;
mat.x = matnum;mat.y = matnum;
for(int i = 0;i < sz;i++)
{
if(!AC.val[i])
{
for(int j = 0;j < child_num;j++)
{
if(!AC.val[AC.chd[i][j]])
mat.v[matcal[i]][matcal[AC.chd[i][j]]]++;
}
}
}
}
Matrix mtMul(Matrix A,Matrix B)
{
if(!A.x || !A.y)return B;
Matrix C;
C.x = A.x;C.y = B.y;
for(int i = 1;i <= A.x;i++)
{
for(int j = 1;j <= B.y;j++)
{
for(int k = 1;k <= A.y;k++)
{
C.v[i][j] = (A.v[i][k] * B.v[k][j] + C.v[i][j]) % mo;
}
}
}
return C;
}
Matrix mtPow(Matrix A,int k)
{
Matrix ret;
while(k)
{
if(k & 1)ret = mtMul(ret,A);
k >>= 1;
A = mtMul(A,A);
}
return ret;
}
void readdata()
{
scanf("%d%d",&m,&n);
AC.Reset();
for(int i = 1;i <= m;i++)
{
scanf("%s",tmp);
AC.Insert(tmp,1);
}
}
void solve()
{
AC.Construct();
work();
Matrix tmp = mtPow(mat,n);
int ans = 0;
for(int i = 1;i <= matnum;i++)
{
ans += tmp.v[1][i];
if(ans >= mo)ans -= mo;
}
printf("%d\n",ans);
}
int main()
{
init();
readdata();
solve();
return 0;
}