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

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

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

那要如何定义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

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
;
 *  + ;
];
][][][];

struct Aho{
    struct StateTable{
        int Next[Letter];
        int fail, cnt;
    }Node[Max_Tot];
    int Size;
    queue<int> que;

    inline void init(){
        while(!que.empty()) que.pop();
        memset(Node[].Next, , ].Next));
        Node[].fail = Node[].cnt = ;
        Size = ;
    }

    inline void insert(char *s){
        ;
        ; s[i]; i++){
            int idx = mp[s[i]];
            if(!Node[now].Next[idx]){
                memset(Node[Size].Next, , sizeof(Node[Size].Next));
                Node[Size].fail = Node[Size].cnt = ;
                Node[now].Next[idx] = Size++;
            }
            now = Node[now].Next[idx];
        }
        Node[now].cnt++;
    }

    inline void BuildFail(){
        Node[].fail = ;
        ; i<Letter; i++){
            ].Next[i]){
                Node[Node[].Next[i]].fail = ;
                que.push(Node[].Next[i]);
            }].Next[i] = ;///必定指向根节点
        }
        while(!que.empty()){
            int top = que.front(); que.pop();
            Node[top].cnt += Node[Node[top].fail].cnt;
            ; i<Letter; i++){
                int &v = Node[top].Next[i];
                if(v){
                    que.push(v);
                    Node[v].fail = Node[Node[top].fail].Next[i];
                }else v = Node[Node[top].fail].Next[i];
            }
        }
    }
}ac;

];
***+][];

int Solve()
{
    ]; memset(num, , sizeof(num));
    ; S[i]; i++) num[mp[S[i]]]++;

    ;
    ; A<=num[]; A++)
        ; T<=num[]; T++)
            ; G<=num[]; G++)
                ; C<=num[]; C++)
                    Hash[A][T][G][C] = HashCnt++;

        ; j<=ac.Size; j++)
            ; i<=HashCnt; i++)
                dp[i][j] = -;

    dp[][] = ;

    ; A<=num[]; A++){
        ; T<=num[]; T++){
            ; G<=num[]; G++){
                ; C<=num[]; C++){
                    ; i<ac.Size; i++){
                        int j = Hash[A][T][G][C];
                        ){
                            ; k<; k++){
                                 && A == num[]) continue;
                                 && T == num[]) continue;
                                 && G == num[]) continue;
                                 && C == num[]) continue;
                                int a, t, g, c;
                                a = (k==), t = (k==);
                                g = (k==), c = (k==);
                                dp[Hash[A+a][T+t][G+g][C+c]][ac.Node[i].Next[k]]
                                = max(dp[Hash[A+a][T+t][G+g][C+c]][ac.Node[i].Next[k]],
                                      dp[j][i] + ac.Node[ac.Node[i].Next[k]].cnt);
                            }
                        }
                    }
                }
            }
        }
    }

    ;
    ]][num[]][num[]][num[]];
    ; i<ac.Size; i++)
        ans = max(ans, dp[MaxNum][i]);

    return ans;
}

int main(void)
{
    ;

    mp[, mp[;
    mp[, mp[;

    while(~scanf("%d", &n) && n){
        ac.init();
        ; i<n; i++){
            scanf("%s", S);
            ac.insert(S);
        }ac.BuildFail();
        scanf("%s", S);
        printf("Case %d: %d\n", Case++, Solve());
    }
    ;
}

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. ElasticSearch入门 —— 集群搭建

    一.环境介绍与安装准备 1.环境说明 2台虚拟机,OS为ubuntu13.04,ip分别为xxx.xxx.xxx.140和xxx.xxx.xxx.145. 2.安装准备 ElasticSearch(简 ...

  2. lnmp一键安装包卸载mysql,重新安装报错mysql57-community-release conflicts with mysql-community-release-el6-5.noarch

    环境:CentOS Linux release 7.6.1810 lnmp1.5 独立下载mysql仓库 wget -i -c http://dev.mysql.com/get/mysql57-com ...

  3. 20191112 Spring Boot官方文档学习(4.3)

    4.3.Profiles Spring Profiles提供了一种隔离部分应用程序配置并使之仅在某些环境中可用的方法.任何@Component,@Configuration或@Configuratio ...

  4. js 中 json.stringfy()将对象、数组转换成字符串

    json.stringfy()将对象.数组转换成字符串 var student = new Object(); student.name = "Lanny"; student.ag ...

  5. Redis进阶:Redis的主从复制机制

    Redis进阶:Redis的主从复制机制 主从复制机制介绍 单机版的Redis存在性能瓶颈,Redis通过提高主从复制实现读写分离,提高了了Redis的可用性,另一方便也能实现数据在多个Redis直接 ...

  6. 剑指Offer编程题(Java实现)——复杂链表的复制

    题目描述 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head.(注意,输出结果中请不要返回参数中的节点引用,否 ...

  7. [pwnable.kr] - wtf

    Q: I don't understand why my exploit is not working. I need your help. download : http://pwnable.kr/ ...

  8. React事件绑定的几种方式对比

    React事件绑定 由于类的方法默认不会绑定this,因此在调用的时候如果忘记绑定,this的值将会是undefined.通常如果不是直接调用,应该为方法绑定this.绑定方式有以下几种: 1. 在构 ...

  9. LeetCode-239-剑指offer-滑动窗口的最大值-队列与栈-python

    给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值.例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6, ...

  10. STL 之 queue

    默认容器为双端队列deque 常用的函数有: empty Test whether container is empty (public member function ) size Return s ...