问至少包含给定的(k)个字符串且长度为(n)的字符串个数
设(dp[i][j][k])表示长度为(i)匹配到AC自动机的节点(j)包含了(k)状态的答案
(dp[0][0][0]=1)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=20090717;
const int maxn=110;
int dp[30][maxn][1<<10],n,m,k;
char s[20];
struct Trie{
int next[maxn][26], fail[maxn], end[maxn];
int last[maxn];
int root, L;
int newnode(){
for (int i = 0; i < 26; i++)
next[L][i] = -1;
fail[L]=last[L]=end[L]=0;
return L++;
}
void init(){
L = 0;
root = newnode();
}
void insert(char buf[],int k){
int len = strlen(buf);
int now = root;
for(int i=0;i<len;i++){
if(next[now][buf[i]-'a'] == -1)
next[now][buf[i]-'a'] = newnode();
now = next[now][buf[i]-'a'];
}
end[now]|=(1<<k);
}
void build(){
queue<int>Q;
fail[root]=root;
for(int i = 0;i < 26;i++){
if(next[root][i]==-1)
next[root][i]=root;
else{
fail[next[root][i]] = root;
Q.push(next[root][i]);
}
}
while(!Q.empty()){
int now = Q.front();
Q.pop();
end[now]|=end[fail[now]]; ///!!!! AC
for(int i = 0;i < 26;i++){
if(next[now][i] == -1)
next[now][i] = next[fail[now]][i];
else{
int son=next[now][i];
fail[son]=next[fail[now]][i];
last[son]=end[fail[son]]?fail[son]:last[fail[son]];
Q.push(next[now][i]);
}
}
}
}
int cal(){
memset(dp,0,sizeof(dp));
dp[0][0][0]=1;
for(int i=0;i<n;i++){
for(int j=0;j<L;j++){
for(int k=0;k<(1<<m);k++){
if(dp[i][j][k]==0)continue;
for(int ii=0;ii<26;ii++){
dp[i+1][next[j][ii]][k|end[next[j][ii]]]+=dp[i][j][k];
dp[i+1][next[j][ii]][k|end[next[j][ii]]]%=mod;
}
}
}
}
int ans=0;
for(int i=0;i<L;i++){
for(int j=0;j<(1<<m);j++){
if(__builtin_popcount(j)>=k){
ans+=dp[n][i][j];
ans%=mod;
}
}
}
return ans;
}
}ac;
int main(){
while(scanf("%d%d%d",&n,&m,&k)){
if(n==0&&m==0&&k==0)break;
ac.init();
for(int i=0;i<m;i++){
scanf("%s",s);
ac.insert(s,i);
}
ac.build();
printf("%d
",ac.cal());
}
return 0;
}