复习一下Ac自动机,我都不会写了。。
这题 Ac+状压Dp,Dp[i][j][k]表示匹配到第i个字符,在Ac自动机里状态为j,与模版串匹配状态为k 的方案数
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
#define N 110
#define Mod 20090717
int n,m,K;
int Dp[30][N][N*10],num[N*10];
struct AcAuto{
int next[N][26],fail[N],end[N];
int root,tot;
int New_node()
{
for(int i=0;i<26;i++)
next[tot][i]=-1;
end[tot++]=0;
return tot-1;
}
void Init()
{
tot=0;
root=New_node();
}
void Insert(char *T,int id)
{
int len=(int)strlen(T);
int now=root;
for(int i=0;i<len;i++)
{
int num=T[i]-'a';
if(next[now][num]==-1)
next[now][num]=New_node();
now=next[now][num];
}
end[now]|=(1<<id);
}
void Build_fail()
{
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]];
for(int i=0;i<26;i++)
{
if(next[now][i]==-1)
next[now][i]=next[fail[now]][i];
else
{
fail[next[now][i]]=next[fail[now]][i];
Q.push(next[now][i]);
}
}
}
}
int Solve()
{
memset(Dp,0,sizeof(Dp));
Dp[0][0][0]=1;
for(int i=0;i<=n;i++)
{
for(int j=0;j<tot;j++)
{
for(int k=0;k<(1<<m);k++)
{
if(Dp[i][j][k]<=0)
continue;
for(int t=0;t<26;t++)
{
int nowi=i+1,nowj=next[j][t],nowk=(k|end[nowj]);
Dp[nowi][nowj][nowk]+=Dp[i][j][k];
Dp[nowi][nowj][nowk]%=Mod;
}
}
}
}
int Ans=0;
for(int i=0;i<(1<<m);i++)
{
if(num[i]>=K)
{
for(int j=0;j<tot;j++)
Ans=(Ans+Dp[n][j][i])%Mod;
}
}
return Ans;
}
};
AcAuto A;
char S[20];
void Prepare()
{
for(int i=0;i<(1<<10);i++)
{
int tmp=i;
while(tmp)
{
if(tmp&1)
num[i]++;
tmp>>=1;
}
}
}
int main()
{
Prepare();
while(scanf("%d%d%d",&n,&m,&K))
{
if(n==0&&m==0&&K==0)
break;
A.Init();
for(int i=0;i<m;i++)
{
scanf("%s",S);
A.Insert(S,i);
}
A.Build_fail();
printf("%d\n",A.Solve());
}
return 0;
}