hdu_2825_Wireless Password(AC自动机+状压DP)

题目链接: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 }
View Code
原文地址:https://www.cnblogs.com/bin-gege/p/5818585.html