题目大意:先给你一些子串,然后给你一个母串,母串里面的字母可以任意调换位置,问最多这个母串经过一些位置变动最多能包含多少个子串。
 
分析:可以比较明显的看出来的DP,先求出来ATGC分别有多少,然后再处理,不过有个比较麻烦的地方,因为ATGC的字母数最多是40,因为不知道那种字母所以是40*40*40*40,很明显这种复杂度太高,开始使用了一次打标,把每种状态都保存下来,并且保存它的下一个状态,不过很不幸这种方法TLE了,因为找他的下一个状态不是太容易,看了大神的题解后明白,其实可以使用4种不同的进制来做,进制数就是这个碱基数的总个数,这样复杂度很明显就降低了,而且状态再转移的时候也很容易。
 
代码如下:
===================================================================================================================================
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std; const int MAXN = ;
const int MaxSon = ;
const int oo = 1e9; int Find(char ch)
{
if(ch == 'A')return ;
if(ch == 'T')return ;
if(ch == 'G')return ; return ;
}
struct Ac_Trie
{
int next[][];
int Fail[], End[];
int root, cnt; int newnode()
{
for(int i=; i<MaxSon; i++)
next[cnt][i] = -;
Fail[cnt] = End[cnt] = false; return cnt++;
}
void InIt()
{
cnt = ;
root = newnode();
}
void Insert(char s[])
{
int now = root; for(int i=; s[i]; i++)
{
int k = Find(s[i]); if(next[now][k] == -)
next[now][k] = newnode();
now = next[now][k];
} End[now] += ;
}
void GetFail()
{
int now = root;
queue<int> Q; for(int i=; i<MaxSon; i++)
{
if(next[now][i] == -)
next[now][i] = root;
else
{
Fail[next[now][i]] = root;
Q.push(next[now][i]);
}
} while(Q.size())
{
now = Q.front();
Q.pop(); for(int i=; i<MaxSon; i++)
{
if(next[now][i] == -)
next[now][i] = next[Fail[now]][i];
else
{
Fail[next[now][i]] = next[Fail[now]][i];
Q.push(next[now][i]);
}
} End[now] += End[Fail[now]];
}
}
};
struct ATGC
{
int sum[], bit[];
int dp[][MAXN];
Ac_Trie ac; void GetSum(char s[])
{
memset(sum, , sizeof(sum));
memset(bit, , sizeof(bit)); for(int i=; s[i]; i++)
{
int k = Find(s[i]);
sum[k]++;
}
}
void GetBit()
{
bit[] = (sum[]+)*(sum[]+)*(sum[]+);
bit[] = (sum[]+)*(sum[]+);
bit[] = sum[]+;
bit[] = ;
}
int GetDp()
{
memset(dp, -, sizeof(dp));
dp[][] = ; int ans = ; for(int A=; A<=sum[]; A++)
for(int T=; T<=sum[]; T++)
for(int G=; G<=sum[]; G++)
for(int C=; C<=sum[]; C++)
{
int k = A*bit[] + T*bit[] + G*bit[] + C*bit[]; for(int i=; i<ac.cnt; i++)
{
if(dp[i][k] == -)continue; for(int j=; j<MaxSon; j++)
{
if(j == && A==sum[])continue;
if(j == && T==sum[])continue;
if(j == && G==sum[])continue;
if(j == && C==sum[])continue; int next = ac.next[i][j];
int nextk = k + bit[j]; dp[next][nextk] = max(dp[next][nextk], dp[i][k]+ac.End[next]);
ans = max(ans, dp[next][nextk]);
}
}
} return ans;
}
}; ATGC a; int main()
{
int i, N, t=; while(scanf("%d", &N), N)
{
char s[];
a.ac.InIt(); for(i=; i<N; i++)
{
scanf("%s", s);
a.ac.Insert(s);
}
a.ac.GetFail(); scanf("%s", s); a.GetSum(s);
a.GetBit(); int ans = a.GetDp(); printf("Case %d: %d\n", t++, ans);
} return ;
}

Lost's revenge - HDU 3341 (自动机+DP)的更多相关文章

  1. 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 ...

  2. Lost's revenge HDU - 3341 AC自动机+DP(需要学会如何优雅的压缩状态)

    题意: 给你n个子串和一个母串,让你重排母串最多能得到多少个子串出现在重排后的母串中. 首先第一步肯定是获取母串中每个字母出现的次数,只有A T C G四种. 这个很容易想到一个dp状态dp[i][A ...

  3. HDU 3341 Lost's revenge (AC自动机 + DP + 变进制/hash)题解

    题意:给你些分数串,给你一个主串,主串每出现一个分数串加一分,要你重新排列主串,最多几分 思路:显然这里开$40^4$去状压内存不够.但是我们自己想想会发现根本不用开那么大,因为很多状态是废状压,不是 ...

  4. HDU3341 Lost's revenge(AC自动机+DP)

    题目是给一个DNA重新排列使其包含最多的数论基因. 考虑到内存大概就只能这么表示状态: dp[i][A][C][G][T],表示包含各碱基个数为ACGT且当前后缀状态为自动机第i的结点的字符串最多的数 ...

  5. 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 ...

  6. HDU 3341 Lost's revenge ( Trie图 && 状压DP && 数量限制类型 )

    题意 : 给出 n 个模式串,最后给出一个主串,问你主串打乱重组的情况下,最多能够包含多少个模式串. 分析 : 如果你做过类似 Trie图 || AC自动机 + DP 类似的题目的话,那么这道题相对之 ...

  7. HDU 2425 DNA repair (AC自动机+DP)

    DNA repair Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  8. hdu 2296 aC自动机+dp(得到价值最大的字符串)

    Ring Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  9. HDU 2457 DNA repair(AC自动机+DP)题解

    题意:给你几个模式串,问你主串最少改几个字符能够使主串不包含模式串 思路:从昨天中午开始研究,研究到现在终于看懂了.既然是多模匹配,我们是要用到AC自动机的.我们把主串放到AC自动机上跑,并保证不出现 ...

随机推荐

  1. sql 作业+游标 自动备份数据库

    前言 昨天有个同事在客户的服务器上面弄数据库,不小心执行了一条 sql 语句 TRUNCATE TABLE xxx 碉堡了吧,数据全没了  - - ,然后就是在网上拼命的搜索关于数据恢复的软件,搞了一 ...

  2. (JAVA)从零开始之--对象输入输出流ObjectInputStream、ObjectOutputStream(对象序列化与反序列化)

    对象的输入输出流 : 主要的作用是用于写入对象信息与读取对象信息. 对象信息一旦写到文件上那么对象的信息就可以做到持久化了 对象的输出流: ObjectOutputStream 对象的输入流:  Ob ...

  3. 【BZOJ2653】【主席树+二分】middle

    Description 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序列s. 回答Q个这样的询问:s的左端点在[a,b ...

  4. photoshop中rgb与索引模式的区别

    RGB: 是色域最宽广的颜色模式它是一种光色模式不难理解  你的显示器 就是根据这个模式来显示图像的同样 我们在自然界中 看到的所有五颜六色的东西都是吸收了不同颜色的光 而得到的所以这一颜色模式 与我 ...

  5. Mobile开发之meta篇

    Mobile开发之meta篇 <meta name="viewport" content="width=device-width, initial-scale=1, ...

  6. Crystal Report制作使用

    Crystal Report制作使用 本文主要划分为以下六部分: 一.Crystal Report for .NET 的功能 二.Crystal Report总体结构 三.报表数据访问执行模式 四.报 ...

  7. 动态改变数据库连接 in Entity Framework 5

    今天把silverlight 升级到5,ADO.ENT EF也用NUGet升级到5.结果发现5下的EF默认没有4的那种分部方法了. 当然你可以把生成器的属性里面,生成代码的属性替换为default,默 ...

  8. sphinx (coreseek)——2、区段查询实例

    首先需要知道区段查询的定义: 索引系统需要通过主查询来获取全部的文档信息,一种简单的实现是将整个表的数据读入内存,但是这可能导致整个表被锁定并使得其他操作被阻止(例如:在MyISAM格式上的INSER ...

  9. 架设wordpress再vps上的 一些感想总结

    日本vps.樱花系列 配置: 2cpu+1G内存+100G硬盘 系统 第一次我把默认的centos 给换了..原因就是,不会linux.而且我主要用.net  感觉 mono也行.但是linux不会. ...

  10. plsql使用之debug

    1. 赋予一个普通用户debug权限 2. 收回权限 SQL> grant DEBUG CONNECT SESSION to bmp; Grant succeeded SQL> revok ...