AC自动机+DP,AC自动机还是把字符串按后缀分类,每个节点记录串的状态为本节点时会包含哪几个所给出的字符串。ans[i][j][k]表示长度为i状态为j包含的所给出的字符串为k(二进制,每一位1,0表示有没有第i个字符串)的字符串的个数。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 #define LL long long 6 using namespace std; 7 const int mod=20090717; 8 const int maxn=11; 9 int ch[maxn*11][26],val[maxn*11],f[maxn*11]; 10 int ans[26][maxn*11][1<<(10)],num[1<<(10)]; 11 int n,m,q,tot,tot2; 12 void Insert(char *s) 13 { 14 int u=0,len=strlen(s),i,tv; 15 for(i=0;i<len;i++) 16 { 17 tv=s[i]-'a'; 18 if(!ch[u][tv]) ch[u][tv]=tot++; 19 u=ch[u][tv]; 20 } 21 val[u]=1<<(tot2++); 22 } 23 void getFail() 24 { 25 queue<int> q; 26 f[0]=0; 27 int i,u; 28 for(i=0;i<26;i++) 29 { 30 u=ch[0][i]; 31 if(u) 32 { 33 f[u]=0; 34 q.push(u); 35 } 36 } 37 int v,r; 38 while(!q.empty()) 39 { 40 r=q.front();q.pop(); 41 for(i=0;i<26;i++) 42 { 43 u=ch[r][i]; 44 if(!u) {ch[r][i]=ch[f[r]][i]; } 45 else 46 { 47 q.push(u); 48 v=f[r]; 49 while(v&&!ch[v][i]) v=f[v]; 50 f[u]=ch[v][i]; 51 val[u]|=val[f[u]]; 52 } 53 } 54 } 55 } 56 int main() 57 { 58 // freopen("1.txt","r",stdin); 59 num[0]=0; 60 int i; 61 for(i=1;i<(1<<10);i++) num[i]=num[i>>1] +(i&1); 62 while(scanf("%d%d%d",&n,&m,&q)) 63 { 64 if(!n&&!m&&!q) break; 65 char s[15]; 66 memset(ch,0,sizeof(ch)); 67 memset(val,0,sizeof(val)); 68 tot=1;tot2=0; 69 for(i=0;i<m;i++) 70 { 71 scanf("%s",s); 72 Insert(s); 73 } 74 getFail(); 75 int j,k,w,v; 76 int M=1<<m; 77 for(i=0;i<=n;++i) 78 for(j=0;j<tot;++j) 79 for(k=0;k<M;++k) 80 ans[i][j][k]=0; 81 ans[0][0][0]=1; 82 for(i=0;i<n;++i) 83 { 84 for(j=0;j<tot;++j) 85 { 86 for(k=0;k<M;++k) 87 { 88 if(!ans[i][j][k]) continue; 89 for(w=0;w<26;w++) 90 { 91 v=ch[j][w]; 92 ans[i+1][v][k|val[v]]=(ans[i+1][v][k|val[v]]+ans[i][j][k])%mod; 93 } 94 } 95 } 96 } 97 int sum=0; 98 for(i=0;i<tot;++i) 99 { 100 for(j=0;j<(1<<m);++j) 101 { 102 if(num[j]>=q) 103 sum=(sum+ans[n][i][j])%mod; 104 } 105 } 106 printf("%d\n",sum); 107 } 108 return 0; 109 }