bzoj1030
AC自动机和DP。
f[i][j] 表示在匹配到第i位置,处于ac自动机的j节点。决策第(i+1)个字母,计算出转移到第j2节点。
f[i+1][j2] += f[i][j];
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxl = 100 + 10; const int maxn = 6000; const int MOD = 10007; char s[maxl]; int a[maxn][26],q[maxn],next[maxn]; int f[maxl][maxn]; bool flag[maxn]; int n,m,cnt=1; void insert(char s[]) { int cur = 1,len = strlen(s); for(int i = 0,c; i < len;i++) { c = s[i] - 'A'; if(a[cur][c]) cur = a[cur][c]; else cur = a[cur][c] = ++cnt; } flag[cur] = 1; } void AC_automaton() { int l=0,r=0,cur; q[r++] = 1,next[1] = 0; while(l < r) { cur = q[l++]; for(int i=0,k;i<26;i++) if(a[cur][i]) { k = next[cur]; while(!a[k][i]) k = next[k]; next[a[cur][i]] = a[k][i]; if(flag[a[k][i]]) flag[a[cur][i]]= 1; q[r++] = a[cur][i]; } } } int main() { scanf("%d%d",&n,&m); for(int i = 0; i < 26; i++) a[0][i] = 1; for(int i = 1; i <= n; i++) scanf("%s",s),insert(s); AC_automaton(); f[0][1] = 1; for(int i = 1; i <= m; i++) { for(int j = 1; j <= cnt; j++) if(!flag[j] && f[i-1][j]) for(int k = 0; k < 26; k++) { int cur = j; while(!a[cur][k]) cur = next[cur]; f[i][a[cur][k]] = (f[i][a[cur][k]]+f[i-1][j])%MOD; } } int res1=1,res2=0; for(int i = 1; i <= m; i++) res1 = (res1*26)%MOD; for(int i = 1; i <= cnt; i++) if(!flag[i]) res2 = (res2+f[m][i])%MOD; printf("%d\n",(res1-res2+MOD)%MOD); return 0; }