题目链接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; }