码迷,mamicode.com
首页 > 其他好文 > 详细

HDU2825 Wireless Password(AC自动机+状压DP)

时间:2016-01-30 13:45:02      阅读:164      评论:0      收藏:0      [点我收藏+]

标签:

题目问长度n至少包含k个咒语的字符串有多少个。也是比较入门的题。。

  • dp[i][j][S]表示长度i(在自动机上转移k步)且后缀状态为自动机上第j个结点且当前包含咒语集合为S的方案数
  • dp[0][0][0]=1
  • 还是用我为人人转移,AC自动机上的结点要多一个域表示这个结点所代表咒语前缀包含的咒语集合。
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<queue>
 4 using namespace std;
 5 int tn,ch[111][26],fail[111],flag[111];
 6 void insert(char *s,int k){
 7     int x=0;
 8     for(int i=0; s[i]; ++i){
 9         int y=s[i]-a;
10         if(ch[x][y]==0) ch[x][y]=++tn;
11         x=ch[x][y];
12     }
13     flag[x]|=1<<k;
14 }
15 void init(){
16     memset(fail,0,sizeof(fail));
17     queue<int> que;
18     for(int i=0; i<26; ++i){
19         if(ch[0][i]) que.push(ch[0][i]);
20     }
21     while(!que.empty()){
22         int x=que.front(); que.pop();
23         for(int i=0; i<26; ++i){
24             if(ch[x][i]) que.push(ch[x][i]),fail[ch[x][i]]=ch[fail[x]][i];
25             else ch[x][i]=ch[fail[x]][i];
26             flag[ch[x][i]]|=flag[ch[fail[x]][i]];
27         }
28     }
29 }
30 int getCnt(int s){
31     int res=0;
32     for(int i=0; i<10; ++i){
33         if((s>>i)&1) ++res;
34     }
35     return res;
36 }
37 int d[26][111][1<<10];
38 int main(){
39     char str[11];
40     int n,m,k;
41     while(~scanf("%d%d%d",&n,&m,&k) && (n||m||k)){
42         tn=0;
43         memset(ch,0,sizeof(ch));
44         memset(flag,0,sizeof(flag));
45         for(int i=0; i<m; ++i){
46             scanf("%s",str);
47             insert(str,i);
48         }
49         init();
50         memset(d,0,sizeof(d));
51         d[0][0][0]=1;
52         for(int i=0; i<n; ++i){
53             for(int j=0; j<=tn; ++j){
54                 for(int k=0; k<(1<<m); ++k){
55                     if(d[i][j][k]==0) continue;
56                     for(int y=0; y<26; ++y){
57                         d[i+1][ch[j][y]][k|flag[ch[j][y]]]+=d[i][j][k];
58                         d[i+1][ch[j][y]][k|flag[ch[j][y]]]%=20090717;
59                     }
60                 }
61             }
62         }
63         int res=0;
64         for(int i=0; i<=tn; ++i){
65             for(int j=0; j<(1<<m); ++j){
66                 if(getCnt(j)<k) continue;
67                 res+=d[n][i][j];
68                 res%=20090717;
69             }
70         }
71         printf("%d\n",res);
72     }
73     return 0;
74 }

 

HDU2825 Wireless Password(AC自动机+状压DP)

标签:

原文地址:http://www.cnblogs.com/WABoss/p/5170699.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!