HDU3341 Lost's revenge(AC自动机&&dp)
一看到ACGT就会想起AC自动机上的dp,这种奇怪的联想可能是源于某道叫DNA什么的题的。
题意,给你很多个长度不大于10的小串,小串最多有50个,然后有一个长度<40的串,然后让你将这个这个长度<40的串经过重新排列之后,小串在里面出现的次数总和最大。譬如如果我的小串是AA,AAC,长串是CAAA,我们重新排列成AAAC之后,AA在里面出现了2次,AAC出现了1次,总和是3次,这个数字就是我们要求的。
思路:思路跟HDU4758 walk through squares很像的,首先对每个小串插Trie树,建自动机,然后要做一下预处理,对于每个状态预处理出到达该状态时匹配了多少个小串,方法就是沿着失配边将cnt加起来。然后对于每个状态,如果它不存在某个字母的后继,就沿着失配边走找到存在该字母的后继,这样预处理后,后面的状态转移起来就比较方便。然后定义状态dp[A][C][G][T][sta]表示已经匹配的A,C,G,T对应为A,C,G,T个,在自动机上的状态为sta时所能匹配到的最大的状态数。然后转移就好。
Trick的部分是,虽然A,C,G,T所能产生的状态数最大是11*11*11*11(即40平均分的时候的情况),但是因为有可能有些字母出现40次,所以开的时候要dp[41][41][41][41][550],想到这里我就不知道怎么写了- -0。后来发现其实可以先hash一下,对于sta[i][j][k][t]=用一个数字s代表其状态,然后开一个数组p[s][0~3]存的是该状态对应的A,C,G,T数,然后再转移就好。
不过貌似跑的有点慢,3s多,感觉挺容易TLE的。
#pragma warning(disable:4996)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<iostream>
#include<queue>
#define maxn 1500
using namespace std; char str[50][15];
char T[50];
int n; void convert(char *s){
int len = strlen(s);
for (int i = 0; i < len; i++){
if (s[i] == 'A') s[i] = 'a';
else if (s[i] == 'C') s[i] = 'b';
else if (s[i] == 'G') s[i] = 'c';
else s[i] = 'd';
}
} struct Trie{
Trie *fail, *go[4];
int cnt; bool flag;
void init(){
memset(go, 0, sizeof(go)); fail = NULL; cnt = 0; flag = false;
}
}pool[maxn],*root;
int tot; void insert(char *c){
int len = strlen(c); Trie *p = root;
for (int i = 0; i < len; i++){
if (p->go[c[i] - 'a'] != 0) p = p->go[c[i] - 'a'];
else{
pool[tot].init();
p->go[c[i] - 'a'] = &pool[tot++];
p = p->go[c[i] - 'a'];
}
}
p->cnt++;
} void getFail()
{
queue<Trie*> que;
que.push(root);
root->fail = NULL;
while (!que.empty()){
Trie *temp = que.front(); que.pop();
Trie *p = NULL;
for (int i = 0; i < 4; i++){
if (temp->go[i] != NULL){
if (temp == root) temp->go[i]->fail = root;
else{
p = temp->fail;
while (p != NULL){
if (p->go[i] != NULL){
temp->go[i]->fail = p->go[i]; break;
}
p = p->fail;
}
if (p == NULL) temp->go[i]->fail = root;
}
que.push(temp->go[i]);
}
}
}
} int dfs(Trie *p){
if (p == root) return 0;
if (p->flag == true) return p->cnt;
p->cnt += dfs(p->fail); p->flag = true;
return p->cnt;
} int sta[45][45][45][45];
int p[15000][4];
int stanum;
int dp[15000][520];
int A, B, C, D; int main()
{
int ca = 0;
while (cin >> n&&n)
{
tot = 0; root = &pool[tot++]; root->init();
for (int i = 0; i < n; i++){
scanf("%s", str[i]); convert(str[i]);
insert(str[i]);
}
scanf("%s", T); A = B = C = D = 0; int len = strlen(T);
for (int i = 0; i < len; i++){
if (T[i] == 'A') A++;
else if (T[i] == 'C') B++;
else if (T[i] == 'G') C++;
else D++;
}
getFail();
for (int i = 0; i < tot; i++) dfs(&pool[i]);
for (int i = 0; i < tot; i++){
Trie *p = &pool[i];
for (int k = 0; k < 4; k++){
if (p->go[k] == NULL){
Trie *temp = p; temp = temp->fail;
while (temp != NULL){
if (temp->go[k] != NULL) {
p->go[k] = temp->go[k]; break;
}
temp = temp->fail;
}
if (temp == NULL) p->go[k] = root;
}
}
}
stanum = 0;
for (int i = 0; i <= A; i++){
for (int j = 0; j <= B; j++){
for (int k = 0; k <= C; k++){
for (int t = 0; t <= D; t++){
sta[i][j][k][t] = stanum;
p[stanum][0] = i; p[stanum][1] = j;
p[stanum][2] = k; p[stanum][3] = t; stanum++;
}
}
}
}
memset(dp, -1, sizeof(dp)); int a, b, c, d;
dp[0][0] = 0;
for (int i = 0; i < stanum; i++){
a = p[i][0]; b = p[i][1]; c = p[i][2]; d = p[i][3];
for (int j = 0; j < tot; j++){
if (dp[i][j] == -1) continue;
if (a + 1 <= A) dp[sta[a + 1][b][c][d]][pool[j].go[0] - pool] =
max(dp[sta[a + 1][b][c][d]][pool[j].go[0] - pool], dp[i][j] + pool[j].go[0]->cnt); if (b + 1 <= B) dp[sta[a][b + 1][c][d]][pool[j].go[1] - pool] =
max(dp[sta[a][b + 1][c][d]][pool[j].go[1] - pool], dp[i][j] + pool[j].go[1]->cnt); if (c + 1 <= C) dp[sta[a][b][c + 1][d]][pool[j].go[2] - pool] =
max(dp[sta[a][b][c + 1][d]][pool[j].go[2] - pool], dp[i][j] + pool[j].go[2]->cnt); if (d + 1 <= D) dp[sta[a][b][c][d + 1]][pool[j].go[3] - pool] =
max(dp[sta[a][b][c][d + 1]][pool[j].go[3] - pool], dp[i][j] + pool[j].go[3]->cnt);
}
}
int ans = 0; int fin = sta[A][B][C][D];
for (int i = 0; i < tot; i++){
ans = max(ans, dp[fin][i]);
}
printf("Case %d: %d\n", ++ca, ans);
}
return 0;
}
HDU3341 Lost's revenge(AC自动机&&dp)的更多相关文章
- HDU 3341 Lost's revenge AC自动机+dp
Lost's revenge Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)T ...
- HDU-3341-Lost's revenge(AC自动机, DP, 压缩)
链接: https://vjudge.net/problem/HDU-3341 题意: Lost and AekdyCoin are friends. They always play "n ...
- hdu3341Lost's revenge(ac自动机+dp)
链接 类似的dp省赛时就做过了,不过这题卡内存,需要把当前状态hash一下,可以按进制来算出当前的状态,因为所有的状态数是不会超过10*10*10*10的,所以完全可以把这些存下来. 刚开始把trie ...
- POJ1625 Censored!(AC自动机+DP)
题目问长度m不包含一些不文明单词的字符串有多少个. 依然是水水的AC自动机+DP..做完后发现居然和POJ2778是一道题,回过头来看都水水的... dp[i][j]表示长度i(在自动机转移i步)且后 ...
- HDU2296 Ring(AC自动机+DP)
题目是给几个带有价值的单词.而一个字符串的价值是 各单词在它里面出现次数*单词价值 的和,问长度不超过n的最大价值的字符串是什么? 依然是入门的AC自动机+DP题..不一样的是这题要输出具体方案,加个 ...
- HDU2457 DNA repair(AC自动机+DP)
题目一串DNA最少需要修改几个基因使其不包含一些致病DNA片段. 这道题应该是AC自动机+DP的入门题了,有POJ2778基础不难写出来. dp[i][j]表示原DNA前i位(在AC自动机上转移i步) ...
- hdu 4117 GRE Words AC自动机DP
题目:给出n个串,问最多能够选出多少个串,使得前面串是后面串的子串(按照输入顺序) 分析: 其实这题是这题SPOJ 7758. Growing Strings AC自动机DP的进阶版本,主题思想差不多 ...
- hdu 2457(ac自动机+dp)
题意:容易理解... 分析:这是一道比较简单的ac自动机+dp的题了,直接上代码. 代码实现: #include<stdio.h> #include<string.h> #in ...
- HDU 2425 DNA repair (AC自动机+DP)
DNA repair Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
随机推荐
- 自学Python二 Python中的屠龙刀(续)
函数 秉承着一切皆对象的理念,函数作为对象,可以为其赋值新的对象名,也可以作为参数传递给其他函数! 正常的诸如空函数,默认参数等等我们就不提了,在这里着重提一下默认参数里面的坑和lambda函数. 当 ...
- C# 编译JS -Evaluator
忘记哪里转过来的,自己mark一下 //// <summary> /// 动态求值 /// </summary> public class Evaluator { /// &l ...
- C扩展 C++回顾到入门
引言 C扩展也称C++, 是一个复(za)杂(ji)优(ken)秀(die)的语言. 本文通过开发中常用C++方式来了解和回顾C++这么语言. C++看了较多的书但还是觉得什么都不会. 只能说自己还付 ...
- 菜鸟学习Spring——60s学会Spring与Hibernate的集成
一.概述. Spring与Hibernate的集成在企业应用中是很常用的做法通过Spring和Hibernate的结合能提高我们代码的灵活性和开发效率,下面我就一步一步的给大家讲述Spring如何和H ...
- AppCan教你从零开始做开发
经常收到类似这样的提问:新手开发APP,要怎么学?我有满屏幕的文档和视频,然而并没有什么卵用,因为我不知道该从哪看起……今天的主要内容是教大家,如何在AppCan移动平台创建应用,引擎插件选择.证书管 ...
- hdu 2648 Shopping
原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=2648 纯暴力的方法T_T... 如下: #include<cstdio> #include ...
- iOS之push present 动画
直接源码: - (void) transitionWithType:(NSString *) type WithSubtype:(NSString *) subtype ForView : (UIVi ...
- [转]KDE/QT与GNOME/GTK比较
[转]KDE/QT与GNOME/GTK比较 http://www.cnblogs.com/itech/archive/2009/08/18/1548964.html 虽然在商业方面存在竞争,GNOME ...
- AngularJs学习笔记-慕课网AngularJS实战
第1章 快速上手 放弃了IE8以及以下,不支持. 4大核心特性: 1.MVC Model: 数据模型 View:视图 Controller:业务逻辑和控制逻辑 好处:职责清晰,模块化. 2.模块化 3 ...
- Python实现LR(逻辑回归)
Python实现LR(逻辑回归) 运行环境 Pyhton3 numpy(科学计算包) matplotlib(画图所需,不画图可不必) 计算过程 st=>start: 开始 e=>end o ...