告诉你一个密码的长度是n,然后给m个单词,并且告诉你这串密码至少包含k个单词(单词可以重叠),求密码可能的种数对20090717取模。一开始脑残把题读错了-看成要包含所有m个单词...WA到死,发现后一改直接A掉了....dp[l][i][sta]表示当前长度为l,在自动机上的i状态,单词包含的状态是sta,然后四重循环,直接按dp[l+1][tree[i][c]][sta|ok[tree[i][c]]]+=dp[l][i][sta]递推就行..复杂度我怎么算都是O(n*AC_SIZE*SIGMA_SIZA*(1<<m)),大约是几千万额...但它居然过了....可能是循环dp[1][i][sta]时,有好多是0的值直接Continue掉了,结果常数小了点吧- -...
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <memory.h>
#include <cmath>
#include <string>
#include <cstring>
#include <queue>
#include <stack>
#include <map>
using namespace std;
typedef long long ll;
const int mod=20090717;
const int maxn=120;
const int tk=26;
int tree[maxn][tk];
int val[maxn];
int last[maxn];
int f[maxn];
int ok[maxn];
int n,m,p,q,k,top;
int dp[36][130][1500];
int num[1500];
inline int idx(char s)
{
return s-'a';
}
struct autoAC
{
void init()
{
top=1;
memset(tree[0],0,sizeof tree[0]);
memset(val,0,sizeof val);
memset(last,0,sizeof last);
memset(f,0,sizeof f);
}
void insert(char* s,int rank)
{
int rt,nxt;
for (rt=0; *s; rt=nxt,++s)
{
nxt=tree[rt][idx(*s)];
if (nxt==0)
{
tree[rt][idx(*s)]=nxt=top;
memset(tree[top],0,sizeof tree[top]);
top++;
}
}
val[rt]|=(1<<rank);
}
void getFail()
{
queue<int> q;
f[0]=0;
for (int c=0; c<tk; c++)
{
int u=tree[0][c];
if (u)
{
q.push(u);
f[u]=0;
last[u]=0;
}
}
while(!q.empty())
{
int r=q.front();
q.pop();
for (int c=0; c<tk; c++)
{
int u=tree[r][c];
if (!u)
{
tree[r][c]=tree[f[r]][c];
continue;
}
q.push(u);
int v=f[r];
while(v && !tree[v][c]) v=f[v];
f[u]=tree[v][c];
last[u]=val[f[u]]?f[u]:last[f[u]];
// ok[u]=val[last[u]]|val[u];
}
}
}
}ac;
void getnum()
{
int res,x;
for (int i=0; i<=1023; i++)
{
x=i;
res=0;
while(x)
{
res+=(x&1);
x>>=1;
}
num[i]=res;
}
}
char s[20],str[20];
int main()
{
// freopen("in.txt","r",stdin);
memset(num,0,sizeof num);
getnum();
while(scanf("%d%d%d",&n,&m,&k) && (n || m || k))
{
gets(str);
// memset(dp,0,sizeof dp);
memset(ok,0,sizeof ok);
ac.init();
for (int i=1; i<=m; i++)
{
gets(str);
ac.insert(str,i-1);
}
ac.getFail();
for (int i=0; i<top; i++)
{
int j=i;
while(j)
{
ok[i]|=val[j];
j=last[j];
}
}
for (int i=0; i<=n; i++)
for (int j=0; j<=top; j++)
for (int k=0; k<=(1<<m); k++)
dp[i][j][k]=0;
dp[0][0][0]=1;
for (int l=0; l<n; l++)
for (int i=0; i<top; i++)
for (int sta=0; sta<(1<<m); sta++)
if (dp[l][i][sta]==0) continue;
else
for (int c=0; c<tk; c++)
{
int nxt=tree[i][c];
int stb=sta|ok[nxt];
dp[l+1][nxt][stb]+=dp[l][i][sta];
if (dp[l+1][nxt][stb]>=mod) dp[l+1][nxt][stb]-=mod;
}
int res=0;
for (int i=0; i<top; i++)
for (int j=0; j<(1<<m); j++)
if (num[j]>=k)
{
res+=dp[n][i][j];
res%=mod;
}
// cout<<endl;
printf("%d\n",res);
}
return 0;
}