HDU 3341 Lost's revenge ( Trie图 && 状压DP && 数量限制类型 )
题意 : 给出 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 && 数量限制类型 )的更多相关文章
- HDU 4758 Walk Through Squares ( Trie图 && 状压DP && 数量限制类型 )
题意 : 给出一个 n 行.m 列的方格图,现从图左上角(0, 0) 到右下角的 (n, m)走出一个字符串(规定只能往下或者往右走),向右走代表' R ' 向下走则是代表 ' D ' 最后从左上角到 ...
- HDU 3920Clear All of Them I(状压DP)
HDU 3920 Clear All of Them I 题目是说有2n个敌人,现在可以发n枚炮弹,每枚炮弹可以(可以且仅可以)打两个敌人,每一枚炮弹的花费等于它所行进的距离,现在要消灭所有的敌人 ...
- HDU 5067 Harry And Dig Machine(状压dp)
HDU 5067 Harry And Dig Machine 思路:因为点才10个,在加上一个起点,处理出每一个点之间的曼哈顿距离,然后用状压dp搞,状态表示为: dp[i][s],表示在i位置.走过 ...
- HDU 3247 Resource Archiver(AC自动机 + 状压DP + bfs预处理)题解
题意:目标串n( <= 10)个,病毒串m( < 1000)个,问包含所有目标串无病毒串的最小长度 思路:貌似是个简单的状压DP + AC自动机,但是发现dp[1 << n][ ...
- HDU - 6125: Free from square (状压DP+分组背包)
problem:给定N,K.表示你有数1到N,让你最多选择K个数,问有多少种方案,使得选择的数的乘积无平方因子数.N,K<500: solution:显然可以状压DP做,但是500以内的素数还是 ...
- HDU 6984 - Tree Planting(数据分治+状压 dp)
题面传送门 傻逼卡常屑题/bs/bs,大概现场过得人比较少的原因就是它比较卡常罢(Fog 首先对于这样的题我们很难直接维护,不过注意到这个 \(n=300\) 给得很灵性,\(k\) 比较小和 \(k ...
- BZOJ 1195 [HNOI2006]最短母串 (Trie图+状压+bfs最短路)
BZOJ1195 LOJ10061 题目大意:给你$n$个模式串,求一个最短且字典序最小的文本串并输出这个串,$n<=12,len<=50$ 首先对所有模式串构造$Trie$图,$Trie ...
- 一本通 高手训练 1782 分层图 状压dp
LINK:分层图 很精辟的一道题 写的时候没带脑子 导致搞了半天不知道哪错了. 可以想到状压每次到某一层的状态 然后这个表示方案数 多开一维表示此时路径条数的奇偶即可. 不过显然我们只需要知道路径条数 ...
- hdu 6086 -- Rikka with String(AC自动机 + 状压DP)
题目链接 Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, s ...
随机推荐
- kafka学习(三)
kafka 消费者-从kafka读取数据 消费者和消费者群里 kafka消费者从属于消费者群组.一个群组里的消费者订阅的是同一主题,每个消费者接受主题一部分分区的消息.如果我们往群组里添加更多的消 ...
- 20191110 Spring Boot官方文档学习(4.1)
4. Spring Boot功能 4.1.Spring应用 便捷的启动方式: public static void main(String[] args) { SpringApplication.ru ...
- [Web 前端] 026 jQuery 初探
目录 1. jQuery 简介 2. jQuery 的简单操作 2.1 jQuery 选择器 2.1.1 简介 2.1.2 基础选择器 2.2 过滤获取 2.3 父子关系获取 3. jQuery 元素 ...
- 块设备驱动——ramblock
一. 什么是块设备. 1.1. 一种具有一定结构的随机存取设备,对这种设备的读写是按块进行的,他使用缓冲区来存放暂时的数据,待条件成熟后,从缓存一次性写入设备或者从设备一次性读到缓冲区.可以随机访问, ...
- python3—廖雪峰之练习(二)
函数的参数练习 请定义一个函数quadratic(a, b, c), 接收3个参数,返回一元二次方程 : $ ax^2+b+c=0 $ 的两个解 提示:计算平方根可以调用math.sqrt()函数: ...
- 小白学Python——用 百度翻译API 实现 翻译功能
本人英语不好,很多词组不认识,只能借助工具:百度翻译和谷歌翻译都不错,近期自学Python,就想能否自己设计一个百度翻译软件呢? 百度翻译开放平台: http://api.fanyi.baidu.co ...
- STL之 stack
栈的常用操作函数:top()push()pop()size()empty() 建栈: stack<int> st; stack<int> st[4]; 四个栈 //可以使用li ...
- 使用pyenv对python版本管理
1.使用pyenv进行python版本管理 1.1安装对应的依赖包,如果不安装后续操作可能会因为缺少某一个变量包而出现错误 sudo apt-get install -y make build- ...
- Java常用日期处理方法
import org.apache.commons.lang3.time.FastDateFormat; import org.joda.time.DateTime; import org.apach ...
- Spring基础16——使用FactoryBean来创建
1.配置bean的方式 配置bean有三种方式:通过全类名(class反射).通过工厂方法(静态工厂&实例工厂).通过FactoryBean.前面我们已经一起学习过全类名方式和工厂方法方式,下 ...