题意 : 给出 n 个模式串,最后给出一个主串,问你主串打乱重组的情况下,最多能够包含多少个模式串。

分析 : 如果你做过类似 Trie图 || AC自动机 + DP 类似的题目的话,那么这道题相对之前的对于主串的“构造”过程加上了一个限制,那就是字符的元素的有限制的,那么DP的状态就不能用长度来表示状态( 类比 POJ 2778 ),所以写出了一个错误的根据长度DP的代码

  1. ; i<len; i++){
  2. ; j<ac.Size; j++){
  3. ){
  4. ; k<; k++){
  5. ){///表示 i、j 状态下,0123代表的“ATGC”字符数还剩多少,但是这是错的,因为在长度为 i 停留在当前节点
  6. ///j 的字符串可能有多种,而这些字符串所拥有的剩余字符数是不一样的,不能单纯只用Lter[i][j][k]表示
  7. ///实际上这只是我自己的理解,我没有打表跟踪过错误数据,你可以自己想想为什么这样子不行……
  8. ;
  9. int newj = ac.Node[j].Next[k];
  10. dp[newi][newj] = max(dp[newi][newj], dp[i][j] + ac.Node[newj].cnt);
  11. ; l<; l++)
  12. Lter[newi][newj][l] = Lter[i][j][l];
  13. Lter[newi][newj][k]--;
  14. }
  15. }
  16. }
  17. }
  18. }

那要如何定义DP状态呢?一般来说对于这样的数量和所在节点状态是关键点,所以我们可以DP[A][T][G][C][Node]前四维表示ATGC数量,最后一维表示当前状态停留在节点 Node ,但是这样子空间会爆炸,这时候就需要压缩一下状态,考虑压缩前四维,网上有很多利用进制的压缩,弱智的我有点不理解,所以还是用了普通的Hash,即利用一个四维数组 Hash[11][11][11][11] ( 每一个字母最多就是 10 个,所以这样开数组 ) ,然后只需要统计主串各个种类字符的数量,就能打出一个 Hash 表,将原本五维DP压成二维DP,DP[i][j] 表示各个字符数量状态为 i 且停留在 j 节点的最多包含模式串个数,则状态转移方程为 ( 一个节点状态能转到"ATGC"四个状态,那么以转到字符 ' A ' 为例 )

DP[ Hash[A+1][G][T][C] ][j] = max( DP[ Hash[A+1][G][T][C] ][j], DP[i][j] + Trie[j]['A'].cnt )

DP初始状态为 DP[0][0] = 0、DP[0~最大的Hash值数量][0~Trie图上的节点个数] = -1

  1. #include<stdio.h>
  2. #include<string.h>
  3. #include<algorithm>
  4. #include<queue>
  5. using namespace std;
  6. ;
  7. * + ;
  8. ];
  9. ][][][];
  10.  
  11. struct Aho{
  12. struct StateTable{
  13. int Next[Letter];
  14. int fail, cnt;
  15. }Node[Max_Tot];
  16. int Size;
  17. queue<int> que;
  18.  
  19. inline void init(){
  20. while(!que.empty()) que.pop();
  21. memset(Node[].Next, , ].Next));
  22. Node[].fail = Node[].cnt = ;
  23. Size = ;
  24. }
  25.  
  26. inline void insert(char *s){
  27. ;
  28. ; s[i]; i++){
  29. int idx = mp[s[i]];
  30. if(!Node[now].Next[idx]){
  31. memset(Node[Size].Next, , sizeof(Node[Size].Next));
  32. Node[Size].fail = Node[Size].cnt = ;
  33. Node[now].Next[idx] = Size++;
  34. }
  35. now = Node[now].Next[idx];
  36. }
  37. Node[now].cnt++;
  38. }
  39.  
  40. inline void BuildFail(){
  41. Node[].fail = ;
  42. ; i<Letter; i++){
  43. ].Next[i]){
  44. Node[Node[].Next[i]].fail = ;
  45. que.push(Node[].Next[i]);
  46. }].Next[i] = ;///必定指向根节点
  47. }
  48. while(!que.empty()){
  49. int top = que.front(); que.pop();
  50. Node[top].cnt += Node[Node[top].fail].cnt;
  51. ; i<Letter; i++){
  52. int &v = Node[top].Next[i];
  53. if(v){
  54. que.push(v);
  55. Node[v].fail = Node[Node[top].fail].Next[i];
  56. }else v = Node[Node[top].fail].Next[i];
  57. }
  58. }
  59. }
  60. }ac;
  61.  
  62. ];
  63. ***+][];
  64.  
  65. int Solve()
  66. {
  67. ]; memset(num, , sizeof(num));
  68. ; S[i]; i++) num[mp[S[i]]]++;
  69.  
  70. ;
  71. ; A<=num[]; A++)
  72. ; T<=num[]; T++)
  73. ; G<=num[]; G++)
  74. ; C<=num[]; C++)
  75. Hash[A][T][G][C] = HashCnt++;
  76.  
  77. ; j<=ac.Size; j++)
  78. ; i<=HashCnt; i++)
  79. dp[i][j] = -;
  80.  
  81. dp[][] = ;
  82.  
  83. ; A<=num[]; A++){
  84. ; T<=num[]; T++){
  85. ; G<=num[]; G++){
  86. ; C<=num[]; C++){
  87. ; i<ac.Size; i++){
  88. int j = Hash[A][T][G][C];
  89. ){
  90. ; k<; k++){
  91. && A == num[]) continue;
  92. && T == num[]) continue;
  93. && G == num[]) continue;
  94. && C == num[]) continue;
  95. int a, t, g, c;
  96. a = (k==), t = (k==);
  97. g = (k==), c = (k==);
  98. dp[Hash[A+a][T+t][G+g][C+c]][ac.Node[i].Next[k]]
  99. = max(dp[Hash[A+a][T+t][G+g][C+c]][ac.Node[i].Next[k]],
  100. dp[j][i] + ac.Node[ac.Node[i].Next[k]].cnt);
  101. }
  102. }
  103. }
  104. }
  105. }
  106. }
  107. }
  108.  
  109. ;
  110. ]][num[]][num[]][num[]];
  111. ; i<ac.Size; i++)
  112. ans = max(ans, dp[MaxNum][i]);
  113.  
  114. return ans;
  115. }
  116.  
  117. int main(void)
  118. {
  119. ;
  120.  
  121. mp[, mp[;
  122. mp[, mp[;
  123.  
  124. while(~scanf("%d", &n) && n){
  125. ac.init();
  126. ; i<n; i++){
  127. scanf("%s", S);
  128. ac.insert(S);
  129. }ac.BuildFail();
  130. scanf("%s", S);
  131. printf("Case %d: %d\n", Case++, Solve());
  132. }
  133. ;
  134. }

HDU 3341 Lost's revenge ( Trie图 && 状压DP && 数量限制类型 )的更多相关文章

  1. HDU 4758 Walk Through Squares ( Trie图 && 状压DP && 数量限制类型 )

    题意 : 给出一个 n 行.m 列的方格图,现从图左上角(0, 0) 到右下角的 (n, m)走出一个字符串(规定只能往下或者往右走),向右走代表' R ' 向下走则是代表 ' D ' 最后从左上角到 ...

  2. HDU 3920Clear All of Them I(状压DP)

    HDU 3920   Clear All of Them I 题目是说有2n个敌人,现在可以发n枚炮弹,每枚炮弹可以(可以且仅可以)打两个敌人,每一枚炮弹的花费等于它所行进的距离,现在要消灭所有的敌人 ...

  3. HDU 5067 Harry And Dig Machine(状压dp)

    HDU 5067 Harry And Dig Machine 思路:因为点才10个,在加上一个起点,处理出每一个点之间的曼哈顿距离,然后用状压dp搞,状态表示为: dp[i][s],表示在i位置.走过 ...

  4. HDU 3247 Resource Archiver(AC自动机 + 状压DP + bfs预处理)题解

    题意:目标串n( <= 10)个,病毒串m( < 1000)个,问包含所有目标串无病毒串的最小长度 思路:貌似是个简单的状压DP + AC自动机,但是发现dp[1 << n][ ...

  5. HDU - 6125: Free from square (状压DP+分组背包)

    problem:给定N,K.表示你有数1到N,让你最多选择K个数,问有多少种方案,使得选择的数的乘积无平方因子数.N,K<500: solution:显然可以状压DP做,但是500以内的素数还是 ...

  6. HDU 6984 - Tree Planting(数据分治+状压 dp)

    题面传送门 傻逼卡常屑题/bs/bs,大概现场过得人比较少的原因就是它比较卡常罢(Fog 首先对于这样的题我们很难直接维护,不过注意到这个 \(n=300\) 给得很灵性,\(k\) 比较小和 \(k ...

  7. BZOJ 1195 [HNOI2006]最短母串 (Trie图+状压+bfs最短路)

    BZOJ1195 LOJ10061 题目大意:给你$n$个模式串,求一个最短且字典序最小的文本串并输出这个串,$n<=12,len<=50$ 首先对所有模式串构造$Trie$图,$Trie ...

  8. 一本通 高手训练 1782 分层图 状压dp

    LINK:分层图 很精辟的一道题 写的时候没带脑子 导致搞了半天不知道哪错了. 可以想到状压每次到某一层的状态 然后这个表示方案数 多开一维表示此时路径条数的奇偶即可. 不过显然我们只需要知道路径条数 ...

  9. hdu 6086 -- Rikka with String(AC自动机 + 状压DP)

    题目链接 Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, s ...

随机推荐

  1. Servlet生命周期 Servlet获取配置信息 ServletContext

    一.Servlet生命周期 实例化 ——> 初始化 ——>  服务 ——>  销毁 出生:(实例化 然后 初始化)tomcat第一次访问,Servlet就出生(默认情况下) 活着:( ...

  2. 【ABAP系列】SAP ABAP 行列转换的方法

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ABAP 行列转换的方法 ...

  3. cocos2dx基础篇(21) 进度条CCProgressTimer

    [3.x] (1)去掉 "CC" (2)CCProgressTimerType 改为强枚举 ProgressTimer::Type:: // RADIAL //扇形进度计时器 BA ...

  4. 跟风Manacher算法整理

    这是上上周天机房一位神仙讲的,\(gu\)了这么久才来整理\(w\),神仙讲的基本思路已经全都忘记了,幸好的是神仙写了\(blog\),吹爆原博浅谈\(Manacher\)算法,以及原博神仙\(ych ...

  5. 数位dp相关

    经典的数位Dp是要求统计符合限制的数字的个数. 一般的形式是:求区间[n,m]满足限制f(1). f(2). f(3)等等的数字的数量是多少. 条件 f(i) 一般与数的大小无关,而与数的组成有关. ...

  6. 洛谷 P2347 砝码称重 & [NOIP1996提高组](dp,枚举)

    传送门 解题思路 一看数据范围<1000就坚定了我暴力的决心(不愧是1996年代的题还是t4QAQ) 所以很显然,暴力之中有一点dp的思想,就是把它们像多重背包一样拆分,拆成a1+a2+a3+a ...

  7. CSP-J&S 2019游记

    $Day -???$ 和爱国爱党的$LQX$书记打了个赌,谁$TG$分低请另一个京味斋. $Day 0$ 机房同学去聚餐,美其名曰"散伙饭",可能又有几个进队的... 我没有去,因 ...

  8. 有序无序Ul->Li Ol->Li菜单,默认点击当前弹出下拉,再次点击收起下拉菜单(变形2 ---修饰)

    从上面可以看出,两个问题,第一:下拉出现的太快太突然,第二:再点击下一个下拉菜单的时候,上一个不会闭合,针对这两个问题,接下来会一 一解决. 解决下拉太快: js中有个jquery效果,有一个效果是j ...

  9. viewset的使用的方法

    viewset的使用方法中是怎么区分的update和crate modelViewSet中设置了这个类之后,设置了类成员变量:queryset 和 seriazlier class,所以POST操作直 ...

  10. python面向对象--元类

    一个类没有声明自己的元类,默认他的元类就是type,除了使用内置元类type,我们也可以通过继承type来自定义元类,然后使用metaclass关键字参数为一个类指定元类 class Foo: def ...