http://acm.hdu.edu.cn/showproblem.php?pid=4057

题意:给出n个子串,串只包含‘A’,'C','G','T'四种字符,你现在需要构造出一个长度为l的串,如果这个串里面包含了某个子串,那么答案就会+val[i](如果这个串被使用过了,就不会再有贡献了),要使得构造出来的串的答案最大,问是多少。

思路:只能想到是AC自动机的题目,然后乱搞出一个错误的方法,没想到是这样的操作。

n只有10,因此才1024,开一个dp[l][sz][st]的数组,l代表当前的字符串长度,sz代表当前遍历的结点,st代表当前的状态(二进制表示使用了哪些字符串),这里的长度用滚动数组优化。

方程:dp[now][nxt[j][x]][k|val[nxt[j][x]]] = dp[pre][j][k]; (当且仅当dp[pre][j][k]状态可取)

nxt[j][x]代表j结点的下一个状态,val[now]代表now这个结点是哪个字符串的终点,因此k|val[nxt[j][x]]就是当前拥有的字符串的状态+下一个结点拥有的字符串的状态。

 #include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define N 1010
#define INF 0x3f3f3f3f
int nxt[N][], fail[N], val[N], rt, sz, n, l, num[];
bool dp[][N][(<<)+];
char s[];
int newnode() {
for(int i = ; i < ; i++) nxt[sz][i] = -;
val[sz++] = ;
return sz - ;
}
void init() {
sz = ; rt = newnode();
}
int Turn(char c) {
if(c == 'A') return ;
if(c == 'C') return ;
if(c == 'G') return ;
return ;
}
void Insert(int id) {
int len = strlen(s);
int now = rt;
for(int i = ; i < len; i++) {
int c = Turn(s[i]);
if(nxt[now][c] == -) nxt[now][c] = newnode();
now = nxt[now][c];
}
val[now] |= ( << id);
}
void Build() {
queue<int> que;
while(!que.empty()) que.pop();
fail[rt] = rt;
for(int i = ; i < ; i++) {
if(nxt[rt][i] == -) nxt[rt][i] = rt;
else fail[nxt[rt][i]] = rt, que.push(nxt[rt][i]);
}
while(!que.empty()) {
int now = que.front(); que.pop();
val[now] |= val[fail[now]]; // 如果fail指向的结点是有状态的,应该加上!!!
for(int i = ; i < ; i++) {
if(nxt[now][i] == -) nxt[now][i] = nxt[fail[now]][i];
else fail[nxt[now][i]] = nxt[fail[now]][i], que.push(nxt[now][i]);
}
}
}
void Solve() {
int pre = , now = ;
memset(dp, , sizeof(dp));
dp[pre][][] = ;
for(int i = ; i < l; i++) {
memset(dp[now], , sizeof(dp[now]));
for(int j = ; j < sz; j++) {
for(int k = ; k < ( << n); k++) {
if(!dp[pre][j][k]) continue;
for(int x = ; x < ; x++) {
dp[now][nxt[j][x]][k|val[nxt[j][x]]] = dp[pre][j][k]; // 哪些状态可以取
// nxt[j][x] 下一个结点
// k | val[nxt[j][x]] 当前状态加上下一个结点有的状态
}
}
}
swap(now, pre);
}
int ans = -INF, res; now = l % ;
for(int i = ; i < sz; i++) {
for(int j = ; j < ( << n); j++) {
if(!dp[now][i][j]) continue;
res = ;
for(int k = ; k < n; k++)
if(j & ( << k)) res += num[k];
ans = ans > res ? ans : res;
}
}
if(ans >= ) printf("%d\n", ans);
else puts("No Rabbit after 2012!");
} int main() {
while(~scanf("%d%d", &n, &l)) {
init();
for(int i = ; i < n; i++) scanf("%s %d", s, &num[i]), Insert(i);
Build();
Solve();
}
return ;
} /*
3 2
A -1
G -1
C -1
*/

HDU 4057:Rescue the Rabbit(AC自动机+状压DP)***的更多相关文章

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

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

  2. hdu 4057--Rescue the Rabbit(AC自动机+状压DP)

    题目链接 Problem Description Dr. X is a biologist, who likes rabbits very much and can do everything for ...

  3. zoj3545Rescue the Rabbit (AC自动机+状压dp+滚动数组)

    Time Limit: 10 Seconds      Memory Limit: 65536 KB Dr. X is a biologist, who likes rabbits very much ...

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

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

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

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

  6. HDU 2825 Wireless Password(AC自动机 + 状压DP)题解

    题意:m个密码串,问你长度为n的至少含有k个不同密码串的密码有几个 思路:状压一下,在build的时候处理fail的时候要用 | 把所有的后缀都加上. 代码: #include<cmath> ...

  7. HDU 4057 Rescue the Rabbit(AC自动机+DP)

    题目链接 一个数组开小了一点点,一直提示wa,郁闷,这题比上个题简单一点. #include <iostream> #include <cstring> #include &l ...

  8. HDU - 2825 Wireless Password (AC自动机+状压DP)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=2825 题意:给一些字符串,构造出长度为n的字符串,它至少包含k个所给字符串,求能构造出的个数. 题解: ...

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

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

  10. BZOJ1559 [JSOI2009]密码 【AC自动机 + 状压dp】

    题目链接 BZOJ1559 题解 考虑到这是一个包含子串的问题,而且子串非常少,我们考虑\(AC\)自动机上的状压\(dp\) 设\(f[i][j][s]\)表示长度为\(i\)的串,匹配到了\(AC ...

随机推荐

  1. [AC自己主动机] zoj Searching the String

    意甲冠军: 到原始字符串.给n字符串,每个字符串都有一个属性,属性0代表重叠,1代表不能重叠 请各多少次出现的字符串 思维: 为了便于建立两台机器自己主动(0一个.1一个) 然后,它可以重叠非常好做, ...

  2. doesn't contain a valid partition table 解决方法

    输入 fdisk -l 可以看到 输入 fdisk /dev/xvdb 跟着向导一步步做下去(如果不知道该输入什么,就输入“m”并回车,可以打印出菜单): Command (m for help): ...

  3. 隐藏在QRCode二维码背后的秘密

    原文:隐藏在QRCode二维码背后的秘密 隐藏在QRCode二维码背后的秘密,您知道吗? 1.容错级. 二维码的容错级分别为:L,M,Q和H.其中,L最低,H最高.如何从二维码中一眼看出其容错级别呢? ...

  4. 通通玩blend美工(6)下——仿iPhone滚动选择器的ListBox(交互逻辑)

    原文:通通玩blend美工(6)下--仿iPhone滚动选择器的ListBox(交互逻辑) 上一篇我们已经把界面画出来了,这篇我们就来制作交互的逻辑吧.上一篇的电梯: http://www.cnblo ...

  5. MVC 自定义路由规则

    using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mv ...

  6. 最好的方式是用VirtualAlloc分配虚拟内存,它既不是在堆也不是在栈,而是直接在进程的地址空间中保留一块内存

    申请效率的比较 栈:由系统自动分配,速度较快.但程序员是无法控制的. 堆:是由new分配的内存,最好的方式是用VirtualAlloc分配虚拟内存,它既不是在堆也不是在栈,而是直接在进程的地址空间中保 ...

  7. ELINK编程器典型场景之远程镜像

    当不想直接提供Hex/Bin等二进制程序文件给用户时,通过生成远程镜像功能将程序文件加密后,再提供给用户自行脱机下载来达到远程更新的目的. 远程镜像生成的一般步骤为由客户端提供SN码,本地依据SN码加 ...

  8. Win10如何设置开机自动登录

    原文:Win10如何设置开机自动登录 第一步: 小娜搜索"netplwiz",进入用户账户设置. 第二步: 先勾选选中一次,要使用本计算机,用户必须输入用户名和密码. 第三步: 取 ...

  9. QAbstractItemView为截断的项显示ToolTip(使用事件过滤)

    在Qt中想要为QAbstractItemView中长度不够而使得内容被截断的项显示ToolTip,Qt官网有一篇文章介绍使用事件过滤器来显示太长的项,但是没有涵盖图标的情况.显示列头项太长的情况等等, ...

  10. 虚拟化代码博客 good

    推荐网站和博客地址 --------------------------------   虚拟化代码博客   QEMU大牛博客:qemu - 韋任的維基百科 http://people.cs.nctu ...