题目链接http://poj.org/problem?id=2778
http://vjudge.net/contest/view.action?cid=51731#problem/E
1.题意
告诉你m个字符串,每个字符串长度不超过10,求长度为n的不包括这m个字符串的串的个数。
2.题解
(1)前提要会构造ac自动机;
(2)构造自动机的目的是做DP,DP_i_j表示长度为i且末尾状态为j的串可以由多少种长度为i-1的状态得到 ,那个DP_i_j=西格玛(DP_i-1_k(0<=k<=top)),用g[i][j]表示长度为0的串到长度为n的串到从状态i转移状态j的路径有多少种(路径有多少种就说明在长度为n的串末尾加一个字符后,不产生病毒串,可以有多少种添加字符的方法)。用自动机构造且判断DP_i-1_k(k为所有状态)到DP_i_j这样的转移是否存在,如果k状态是end态(说明走到了病毒上面了),则转移不存在;如果k状态是 !end 态,且k状态的fail态全都是!end态(在构造自动机的时候,每bfs一个状态时就可以每次判断一次他的fail转移是不是end态,如果是end态,就说明他的后缀有病毒,不管他到底是不是end态,也都要改变成end态),如果next[k][c]有边(不管是fail转移到j状态,还是接受后转移到j状态都算)可以到j状态,则转移存在,那就用矩阵把对于的g[k][j]加一。
(3)初次求得g[][]矩阵时,它表示从字符串长度0到字符串长度1,状态i到状态j之间的转移可以有几种,只要求出g[][]的n次方,就可以知道从字符串长度0到字符串长度n,状态i到状态j之间的转移可以有几种;
code:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
/**
5 4
AAA
ATA
T
TA
TAA
初始矩阵
2 1 0 0 0 0 0 0 0
2 0 1 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0
处理后的矩阵
52 18 6 0 0 0 0 0 0
48 16 6 0 0 0 0 0 0
36 12 4 0 0 0 0 0 0
36 12 4 0 0 0 0 0 0
36 12 4 0 0 0 0 0 0
36 12 4 0 0 0 0 0 0
36 12 4 0 0 0 0 0 0
36 12 4 0 0 0 0 0 0
36 12 4 0 0 0 0 0 0
76
**/
#define Clear(x) memset(x,0,sizeof x)
typedef long long LL;
const int MAXN=108,MAX=4,MOD=100000;
int sz;
struct Mat{
int m[MAXN][MAXN];
Mat(){Clear(m);}
Mat(int x){
Clear(m);
for(int i=0;i<sz;i++)
m[i][i]=x;
}
};
Mat operator*(Mat a,Mat b){
Mat ret;
int i,j,k;
for(i=0;i<sz;i++)
for(j=0;j<sz;j++){
if(a.m[i][j]==0) continue;
for(k=0;k<sz;k++){
int tmp=((LL)a.m[i][j]*b.m[j][k])%MOD;
ret.m[i][k]=(ret.m[i][k]+tmp)%MOD;
}
}
return ret;
}
Mat Pow(Mat a,int b){
Mat ret(1);
while(b){
if(b&1)ret=ret*a;
a=a*a;
b>>=1;
}
return ret;
}
Mat dp;
int ch[MAXN][MAX],f[MAXN],top;
bool end[MAXN];
int idx(char ch){
switch(ch){
case 'A':return 0;
case 'C':return 1;
case 'G':return 2;
}
return 3;//T
}
void init(){
top=0;
Clear(end);
Clear(f);Clear(ch);
}
int NewNode(){return ++top;}
void insert(char *s,int num){
int x=0,n=strlen(s);
for(int i=0;i<n;i++){
int c=idx(s[i]);
if(!ch[x][c]) ch[x][c]=NewNode();
x=ch[x][c];
}
end[x]=true;
}
void getFail(){
queue<int>Q;
for(int c=0;c<MAX;c++){
int &u=ch[0][c];
if(u)Q.push(u);
}
while(!Q.empty()){
int r=Q.front();Q.pop();
if(end[f[r]])//!!!
end[r]=true;
for(int c=0;c<MAX;c++){
int u=ch[r][c];
int v=f[r];
if(!u){ch[r][c]=ch[v][c];continue;}
Q.push(u);
while(v && !ch[v][c]) v=f[v];
f[u]=ch[v][c];
}
}
}
void getDP(){
Clear(dp.m);
for(int i=0;i<=top;i++){
for(int j=0;j<MAX;j++){
if(!end[ch[i][j]]) dp.m[i][ch[i][j]]++;
}
}
}
int main()
{
// freopen("data.in","r",stdin);
int n,m;
char P[20];
while(scanf("%d%d",&n,&m)==2){
init();
for(int i=1;i<=n;i++){
scanf("%s",P);
insert(P,i);
}
getFail();
sz=top+1;
getDP();
dp=Pow(dp,m);
int ans=0;
for(int i=0;i<sz;i++){
ans+=dp.m[0][i];
ans%=MOD;
}
printf("%d\n",ans);
}
return 0;
}