HDU2825Wireless PasswordAC自动机,状态压缩DP
Posted lqllulu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU2825Wireless PasswordAC自动机,状态压缩DP相关的知识,希望对你有一定的参考价值。
题意
题目给出m(m<=10)个单词,每个单词的长度不超过10且仅由小写字母组成,给出一个正整数n(n<=25)和正整数k,问有多少方法可以组成长度为n的文本且最少包含k个给出的单词。
分析
和上一个AC自动机很相似,上一篇博客是不包含任何一个单词长度为n的方案数,这个题是包含至少k个单词的方案数,而且n,m,k都非常的小。
按照前面的经验很容易想到,我们还是得先建一个AC自动机,然后把它的单词结点标记出来。与前面不同的是我们在状态转移的时候需要考虑到当前走过的结点已经包含多少单词了。所以我们想到用dp[i][j][k]来表示当前在i结点,已经走了j步,且走过了k个单词结点。但是我们发现,这样表示状态的话没有办法转移,因为当我们遇到一个单词结点的时候,我们并不知道这个单词节点前面时候已经走过被计数了。所以我们想到,要使用状态压缩dp来解决这个题目。
f[i][j][S]当前在i结点,还需要走j步,包含的结点由S通过二进制来表示。在建AC自动机的时候,用match[i]=1<<j,来表示i结点是单词j的单词结点。
f[i][j][S]=sum(f[v][j-1][S|match[v]]).其中v是结点i的儿子结点。
当j==0时,如果S中包含的单词数目>=k,则f[i][0][S]=1,否则为0
然后我们就很容易用记忆搜索解决这个问题。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <queue> 6 7 using namespace std; 8 const int maxnode=110; 9 const int MOD=20090717; 10 const int sigma_size=26; 11 int ch[maxnode][sigma_size],match[maxnode],f[maxnode]; 12 int dp[maxnode][30][(1<<10)+100],vis[maxnode][30][(1<<10)+100]; 13 int sz; 14 void init(){ 15 sz=1; 16 memset(ch[0],0,sizeof(ch[0])); 17 memset(vis,0,sizeof(vis)); 18 match[0]=0; 19 } 20 void insert(char *s,int v){ 21 int n=strlen(s),u=0; 22 for(int i=0;i<n;i++){ 23 int c=s[i]-‘a‘; 24 if(!ch[u][c]){ 25 ch[u][c]=sz; 26 memset(ch[sz],0,sizeof(ch[sz])); 27 match[sz++]=0; 28 } 29 u=ch[u][c]; 30 } 31 match[u]|=(1<<v); 32 } 33 34 void getFail(){ 35 queue<int>q; 36 f[0]=0; 37 for(int i=0;i<sigma_size;i++){ 38 int u=ch[0][i]; 39 if(u){ 40 q.push(u); 41 f[u]=0; 42 } 43 } 44 while(!q.empty()){ 45 int r=q.front();q.pop(); 46 for(int i=0;i<sigma_size;i++){ 47 int u=ch[r][i]; 48 if(!u){ 49 ch[r][i]=ch[f[r]][i]; 50 continue; 51 } 52 q.push(u); 53 int v=f[r]; 54 while(v&&!ch[v][i])v=f[v]; 55 f[u]=ch[v][i]; 56 match[u]|=match[f[u]]; 57 } 58 } 59 } 60 int n,m,k; 61 char s[20]; 62 int Count(int S){ 63 int res=0; 64 for(int i=0;i<m;i++){ 65 if(S&(1<<i)) 66 res++; 67 } 68 return res; 69 } 70 int DP(int u,int L,int S){ 71 if(vis[u][L][S]) 72 return dp[u][L][S]; 73 vis[u][L][S]=1; 74 int &ans=dp[u][L][S]; 75 ans=0; 76 if(L==0){ 77 if(Count(S)>=k){ 78 return ans=1; 79 } 80 return ans=0; 81 } 82 for(int i=0;i<sigma_size;i++){ 83 int v=ch[u][i]; 84 ans=(ans%MOD+DP(v,L-1,S|match[v])%MOD)%MOD; 85 } 86 return ans; 87 } 88 int main(){ 89 while(scanf("%d%d%d",&n,&m,&k)!=EOF&&(n||m||k)){ 90 init(); 91 for(int i=0;i<m;i++){ 92 scanf("%s",s); 93 insert(s,i); 94 } 95 getFail(); 96 int ans=DP(0,n,0); 97 printf("%d ",ans%MOD); 98 } 99 return 0; 100 }
以上是关于HDU2825Wireless PasswordAC自动机,状态压缩DP的主要内容,如果未能解决你的问题,请参考以下文章
HDU 2825 Wireless Password(AC自动机)
HDU2825 Wireless Password(AC自动机+状压DP)
HDU 2825 Wireless Password AC自动机+dp