给m个单词,问构造长为n且含有至少k个单词的串的种数
朴素的自动机上DP,遍历了自动机的所有状态,dp[i][j][k]:长为i的串匹配到状态j,出现k编码状态word的串的种数
#include<bits/stdc++.h>
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<iostream>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<iomanip>
using namespace std;
#define ll long long
#define ull unsigned long long
#define pb push_back
#define FOR(a) for(int i=1;i<=a;i++)
const int inf=0x3f3f3f3f;
const int maxn=140+9;
const int mod=20090717;
const int sigma=26;
int n,m,k;
int dp[30][110][1<<10];
//dp[i][j][k]:长度为i的串匹配到状态j,出现了k状态word的串个数
int num[5005]; //num[i]:i有多少个二进制为1位
struct automata{
int ch[maxn][sigma];
int val[maxn];
int f[maxn];
int sz;
int newnode(){
memset(ch[sz],0,sizeof(ch[sz]));
f[sz]=val[sz]=0;
return sz++;
}
void init(){
memset(val,0,sizeof(val));
sz=0;
newnode();
}
void insert(char *s,int v){
int u=0;
int len=strlen(s);
for(int i=0;i<len;i++){
int id=s[i]-'a';//s[i]-'a';
if(!ch[u][id])ch[u][id]=newnode();
u=ch[u][id];
}
val[u]|=(1<<v);
}
void build(){
queue<int>q;
q.push(0);
while(!q.empty()){
int u=q.front();q.pop();
val[u]|=val[f[u]];
for(int i=0;i<sigma;i++){
int v=ch[u][i];
if(!v)ch[u][i]=ch[f[u]][i];
else q.push(v);
if(u&&v)f[v]=ch[f[u]][i];
}
}
}
int work(){
for(int i=0;i<=n;i++){
for(int j=0;j<sz;j++){
for(int p=0;p<(1<<m);p++){
dp[i][j][p]=0;
}
}
}
dp[0][0][0]=1;
for(int i=0;i<n;i++){
for(int j=0;j<sz;j++){
for(int p=0;p<(1<<m);p++){
if(dp[i][j][p]>0){
for(int c=0;c<26;c++){
int nxti=i+1;
int nxtj=ch[j][c];
int nxtp=(p|val[nxtj]);
dp[nxti][nxtj][nxtp]+=dp[i][j][p];
dp[nxti][nxtj][nxtp]%=mod;
}
}
}
}
}
int ans=0;
for(int p=0;p<(1<<m);p++){
if(num[p]<k)continue; //剪枝,至少有k个位
for(int i=0;i<sz;i++){
ans=(ans+dp[n][i][p])%mod;
}
}
return ans;
}
}ac;
char s[20];
int main(){
for(int i=0;i<(1<<10);i++){
num[i]=0;
for(int j=0;j<10;j++){
if(i & (1<<j))num[i]++;
}
}
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\n",ac.work());
}
}