链接:点击打开链接
题意:求一个长度是n的字符串至少含有给出的m个字符串中的k个的种数
代码:
#include <set>
#include <queue>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int MOD=20090717;
struct node{
int c[26],dis,fail;
}s[105];
int n,m,K,rt;
int dp[30][105][(1<<10)+5];
void in(char ss[],int id){
int i,u;
u=0;
for(i=0;ss[i];i++){
if(s[u].c[ss[i]-'a']==0)
s[u].c[ss[i]-'a']=rt++;
u=s[u].c[ss[i]-'a'];
}
s[u].dis|=(1<<id);
}
void getfail(){
int i,u,v,tmp;
queue<int> qu;
qu.push(0);
while(qu.size()){
u=qu.front();
qu.pop();
for(i=0;i<26;i++){
if(v=s[u].c[i]){
if(u==0)
s[v].fail=0;
else{
tmp=s[u].fail;
if(tmp&&s[tmp].c[i]==0)
tmp=s[tmp].fail;
s[v].fail=s[tmp].c[i];
s[v].dis|=s[s[tmp].c[i]].dis;
} //转移fail的同时,转移状态
qu.push(v);
}
else
s[u].c[i]=s[s[u].fail].c[i];
}
}
}
int ac(){
int i,j,k,p,ans,sta,tmp;
memset(dp,0,sizeof(dp));
dp[0][0][0]=1;
getfail();
for(i=0;i<n;i++){ //dp[i][j][k]表示长度是i走到第j个节点,状态是k的种数
for(j=0;j<rt;j++){
for(sta=0;sta<(1<<m);sta++){
if(dp[i][j][sta]>0)
for(p=0;p<26;p++){
tmp=dp[i+1][s[j].c[p]][sta|(s[s[j].c[p]].dis)];
tmp=(tmp+dp[i][j][sta])%MOD;
dp[i+1][s[j].c[p]][sta|(s[s[j].c[p]].dis)]=tmp;
}
}
}
}
ans=0;
for(i=0;i<rt;i++){
for(j=0;j<(1<<m);j++){
if(__builtin_popcount(j)>=K) //大于k的计数
ans=(ans+dp[n][i][j])%MOD;
}
}
return ans;
}
int main(){
int i,j;
char ss[15];
while(scanf("%d%d%d",&n,&m,&K)!=EOF&&(n||m||K)){
rt=1;
memset(s,0,sizeof(s));
for(i=0;i<m;i++){
scanf("%s",ss);
in(ss,i);
}
printf("%d\n",ac());
}
return 0;
}