题目链接:hdu_2825_Wireless Password
题意:
给你m个串,问长度为n至少含k个串的字符串有多少个
题解:
设dp[i][j][k]表示考虑到长度为i,第j个自动机的节点,含有k这个压缩状态的方案数,然后DP下去就行了
1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;i++) 3 using namespace std; 4 5 const int mod=20090717; 6 const int AC_N=10*51,tyn=26;//数量乘串长,类型数 7 struct AC_automation{ 8 int tr[AC_N][tyn],cnt[AC_N],Q[AC_N],fail[AC_N],tot; 9 inline int getid(char x){return x-'a';} 10 void nw(){cnt[++tot]=0,fail[tot]=0;memset(tr[tot],0,sizeof(tr[tot]));} 11 void init(){tot=-1,fail[0]=-1,nw();} 12 void insert(char *s,int ids,int x=0){ 13 for(int len=strlen(s),i=0,w;i<len;x=tr[x][w],i++) 14 if(!tr[x][w=getid(s[i])])nw(),tr[x][w]=tot; 15 cnt[x]|=1<<ids;//串尾标记 16 } 17 void build(int head=1,int tail=0){ 18 for(int i=0;i<tyn;i++)if(tr[0][i])Q[++tail]=tr[0][i]; 19 while(head<=tail)for(int x=Q[head++],i=0;i<tyn;i++) 20 if(tr[x][i])fail[tr[x][i]]=tr[fail[x]][i],Q[++tail]=tr[x][i],cnt[tr[x][i]]|=cnt[tr[fail[x]][i]]; 21 else tr[x][i]=tr[fail[x]][i]; 22 } 23 }AC; 24 25 char s[111]; 26 int dp[26][111][1<<11],n,m,k,ans; 27 28 inline int getans(int s,int an=0) 29 { 30 F(i,0,9)if((s>>i)&1)an++; 31 return an; 32 } 33 34 int main() 35 { 36 while(~scanf("%d%d%d",&n,&m,&k)&&(n||m||k)) 37 { 38 AC.init(),ans=0; 39 F(i,0,m-1)scanf("%s",s),AC.insert(s,i); 40 AC.build(); 41 memset(dp,0,sizeof(dp)),dp[0][0][0]=1; 42 F(i,0,n-1)F(j,0,AC.tot)for(int k=0;k<(1<<m);++k) 43 if(dp[i][j][k]!=0)F(ii,0,25) 44 { 45 int *p=&dp[i+1][AC.tr[j][ii]][k|AC.cnt[AC.tr[j][ii]]]; 46 *p=(*p+dp[i][j][k])%mod; 47 } 48 F(i,0,AC.tot)for(int j=0;j<(1<<m);j++)if(getans(j)>=k)ans=(ans+dp[n][i][j])%mod; 49 printf("%d ",ans); 50 } 51 return 0; 52 }