题目大意:有个人想破解他邻居的密码,他邻居告诉了一些关于这个密码的信息,并且给他一个单词集合,他用这些信息判断一下最少有多少种密码。
1->, 所有的密码都是有小写字母组成。
2->,密码的长度是 n (1<= n <=25)。
3->,密码至少包含 k 种字符集里面的单词。
 
比如,给集合{"she", "he"},单词长度是3,最少包含两个单词的密码,很明显只能是“she”(题目表述的不清楚)。
 
分析:因为要统计记录到达每个点时候经过多少种不同的单词,所以需要用一种方法来保存这些信息,开一个数组来判重貌似是个很容易想到的办法,不过考虑时间复杂度的问题,建议还是不要这么干,因为字符集合的数量很少,只有10,所以我们可以使用状态压缩来保存这些信息,而且转移状态时候也很方便操作,不过有点需要注意,一定要把遍历子节点放在最内层循环,这样再遍历每一种状态的时候发先有0的情况可以continue一下,否则超时超的哇哇的.......
 
代码如下:
==========================================================================
  1. #include<iostream>
  2. #include<algorithm>
  3. #include<stdio.h>
  4. #include<string.h>
  5. #include<queue>
  6. using namespace std;
  7.  
  8. const int MAXN = ;
  9. const int MaxSon = ;
  10. const int Mod = ;
  11. const int oo = 1e9+;
  12.  
  13. struct Ac_Trie
  14. {
  15. int next[MAXN][MaxSon];
  16. int Fail[MAXN], End[MAXN];
  17. int cnt, root;
  18.  
  19. int newnode()
  20. {
  21. for(int i=; i<MaxSon; i++)
  22. next[cnt][i] = -;
  23. Fail[cnt] = End[cnt] = false;
  24.  
  25. return cnt++;
  26. }
  27. void InIt()
  28. {
  29. cnt = ;
  30. root = newnode();
  31. }
  32.  
  33. void Insert(char s[], int t)
  34. {
  35. int now = root;
  36.  
  37. for(int i=; s[i]; i++)
  38. {
  39. int k = s[i]-'a';
  40.  
  41. if(next[now][k] == -)
  42. next[now][k] = newnode();
  43. now = next[now][k];
  44. }
  45.  
  46. End[now] = <<t;
  47. }
  48. void GetFial()
  49. {
  50. queue<int>Q;
  51. int now = root;
  52.  
  53. for(int i=; i<MaxSon; i++)
  54. {
  55. if(next[now][i] == -)
  56. next[now][i] = root;
  57. else
  58. {
  59. Fail[next[now][i]] = root;
  60. Q.push(next[now][i]);
  61. }
  62. }
  63.  
  64. while(Q.size())
  65. {
  66. now = Q.front();
  67. Q.pop();
  68.  
  69. for(int i=; i<MaxSon; i++)
  70. {
  71. if(next[now][i] == -)
  72. next[now][i] = next[Fail[now]][i];
  73. else
  74. {
  75. Fail[next[now][i]] = next[Fail[now]][i];
  76. Q.push(next[now][i]);
  77. }
  78. }
  79.  
  80. End[now] |= End[Fail[now]];
  81. }
  82. }
  83. };
  84. Ac_Trie ac;
  85.  
  86. int Find(int i)
  87. {
  88. int k=;
  89.  
  90. while(i)
  91. {
  92. if(i % )
  93. k++;
  94. i /= ;
  95. }
  96.  
  97. return k;
  98. }
  99.  
  100. int main()
  101. {
  102. int N, M, K;
  103.  
  104. int sum[] ={};
  105.  
  106. for(int i=; i<; i++)
  107. sum[i] = Find(i);
  108.  
  109. while(scanf("%d%d%d", &N, &M, &K), N+M+K)
  110. {
  111. char s[MAXN];
  112. ac.InIt();
  113.  
  114. for(int i=; i<M; i++)
  115. {
  116. scanf("%s", s);
  117. ac.Insert(s, i);
  118. }
  119.  
  120. ac.GetFial();
  121.  
  122. int dp[][MAXN][] = {}, op=, Len = <<M;
  123. dp[][][] = ;
  124.  
  125. while(N--)
  126. {
  127. memset(dp[op], , sizeof(dp[op]));
  128.  
  129. for(int i=; i<ac.cnt; i++)
  130. for(int k=; k<Len; k++)
  131. {///把k放中间优化一下...否则超时
  132. if(dp[op^][i][k] == )
  133. continue;
  134.  
  135. for(int j=; j<MaxSon; j++)
  136. {
  137. (dp[op][ac.next[i][j]][k|ac.End[i]] += dp[op^][i][k])%=Mod;
  138. }
  139. }
  140.  
  141. op ^= ;
  142. }
  143.  
  144. int ans = ;
  145.  
  146. for(int i=; i<ac.cnt; i++)
  147. for(int j=; j<Len; j++)
  148. {
  149. if(sum[j] >= K || sum[ac.End[i]|j] >= K)
  150. {
  151. ans += dp[op^][i][j];
  152. ans %= Mod;
  153. }
  154. }
  155.  
  156. printf("%d\n", ans);
  157. }
  158.  
  159. return ;
  160. }

Wireless Password - HDU 2825(ac自动机+状态压缩)的更多相关文章

  1. hdu 2825(ac自动机+状态压缩dp)

    题意:容易理解... 分析:在做这道题之前我做了hdu 4057,都是同一种类型的题,因为题中给的模式串的个数最多只能为10个,所以我们就很容易想到用状态压缩来做,但是开始的时候我的代码超时了dp时我 ...

  2. HDU 4511 (AC自动机+状态压缩DP)

    题目链接:  http://acm.hdu.edu.cn/showproblem.php?pid=4511 题目大意:从1走到N,中间可以选择性经过某些点,比如1->N,或1->2-> ...

  3. hdu 4057(ac自动机+状态压缩dp)

    题意:容易理解... 分析:题目中给的模式串的个数最多为10个,于是想到用状态压缩dp来做,它的状态范围为1-2^9,所以最大为2^10-1,那我们可以用:dp[i][j][k]表示长度为i,在tri ...

  4. hdu 3341(ac自动机+状态压缩)

    题意:容易理解... 思路:首先一开始容易想到要用到dp,开设一个dp[41][41][41][41][501]的数组来解决,但是明显内存已经超出范围了,于是就想如何减少内存呢?只要知道A.T.C.G ...

  5. hdu 2825 aC自动机+状压dp

    Wireless Password Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...

  6. HDU 4057 Rescue the Rabbit ( AC自动机 + 状态压缩DP )

    模板来自notonlysuccess. 模式串只有10个,并且重复出现的分值不累加,因此很容易想到状态压缩. 将模式串加入AC自动机,最多有10*100个状态. dp[i][j][k]:串长为i,在T ...

  7. HDU 4758 Walk Through Squares( AC自动机 + 状态压缩DP )

    题意:给你两个串A,B, 问一个串长为M+N且包含A和B且恰好包含M个R的字符串有多少种组合方式,所有字符串中均只含有字符L和R. dp[i][j][k][S]表示串长为i,有j个R,在自动机中的状态 ...

  8. POJ 3691 (AC自动机+状态压缩DP)

    题目链接:  http://poj.org/problem?id=3691 题目大意:给定N个致病DNA片段以及一个最终DNA片段.问最终DNA片段最少修改多少个字符,使得不包含任一致病DNA. 解题 ...

  9. bzoj1195 神奇的ac自动机+状态压缩dp

    /* 难的不是ac自动机,是状态压缩dp 之前做了一两题类似题目,感觉理解的还不够透彻 */ #include<iostream> #include<cstdio> #incl ...

随机推荐

  1. SQL Server Management Studio的对象资源管理器的使用

    1.查看 2.对象资源管理器 3.点到某个表的身上 4.出现以下图片,因为有时动态创建的触发器,刷新表下面的触发器可能不出来,所以来这里面找

  2. 微信小程序开发之 下拉刷新,上拉加载更多

    本文记载了如何在微信小程序里面实现下拉刷新,上拉加载更多 先开看一下界面 大致如此的界面吧. 这个Demo使用了微信的几个Api和事件,我先列出来. 1.wx.request (获取远程服务器的数据, ...

  3. topcoder算法练习3

    SRM144 DIV1 1100 point Problem Statement      NOTE: There are images in the examples section of this ...

  4. alsa utils工具使用

    1.amixer用于控制设置 amixer [-c card] [cmd] ./amixer contents ./amixer cset ./amixer cget 2. aplay ./aplay ...

  5. Bootstrap_Javascript_按钮插件

    一 . 加载状态按钮 HTML: <button class="btnbtn-primary" data-loading-text="正在加载中,请稍等...&qu ...

  6. css中文字体乱码解决方案

    css中文字体乱码解决方案:把css编码和html页面编码统一起来.如果html页面是utf-8.css.js也统一成utf-8编码.还有一个避免中文乱码的办法就是把中文字体写成英文来表示 css中文 ...

  7. javascript实现ajax

    什么是 ajax ajax 即“Asynchronous JavaScript and XML”(异步 JavaScript 和 XML),也就是无刷新数据读取. http 请求 首先需要了解 htt ...

  8. 简单学C——第一天

    基本功 一.数据类型: 在C语言中,有数据类型这一说法.为何有这一说法?是因为在现实生活中存在着不同的数据,(例如整数,小数,字符即a b c d , . ; "  之类).由于计算机中所有 ...

  9. 用硬件(Verilog)实现二进制码和格雷码的转换

    格雷码(Gray code)是1880年由法国工程师Jean-Maurice-Emlle Baudot发明的一种编码,是一种绝对编码方式,典型格雷码是一种具有反射特性和循环特性的单步自补码,它的循环. ...

  10. C语言中的字节对齐以及其相关处理

    首先,我们来了解下一些基本原理: 一.什么是字节对齐一个基本类型的变量在内存中占用n个字节,则该变量的起始地址必须能够被n整除,即: 存放起始地址 % n = 0,那么,就成该变量是字节对齐的;对于结 ...