模板来自notonlysuccess.

模式串只有10个,并且重复出现的分值不累加,因此很容易想到状态压缩。

将模式串加入AC自动机,最多有10*100个状态。

dp[i][j][k]:串长为i,在Trie图上的状态为j,已经包含的模式串为k(二进制表示,第x位为1代表已经包含第x个串)。

dp[i][j][k]为true或false代表该状态是否可达。

沿着Trie图中的边走进行DP,时间复杂度O( 100*1000*1024 );

最后枚举一下串长为L的所有可达状态,最大值即为结果。

PS.内存有限,需要用滚动数组

PS2.若使用静态队列的话,队列大小最好开状态数的二倍或者更多

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring> using namespace std; const int MAX_NODE = ;
const int CHILD_NUM = ;
const int MAXN = ;
const int INF = << ; struct ACAutomaton
{
int chd[MAX_NODE][CHILD_NUM]; //每个节点的儿子,即当前节点的状态转移
int val[MAX_NODE]; //记录题目给的关键数据
int fail[MAX_NODE]; //传说中的fail指针
int Q[MAX_NODE<<]; //队列,用于广度优先计算fail指针
int ID[]; //字母对应的ID
int sz; //已使用节点个数 //初始化,计算字母对应的儿子ID,如:'a'->0 ... 'z'->25
void Initialize()
{
fail[] = ;
ID['A'] = ;
ID['G'] = ;
ID['C'] = ;
ID['T'] = ;
return;
}
//重新建树需先Reset
void Reset()
{
memset(chd[] , , sizeof(chd[]));
val[] = ;
sz = ;
}
//将权值为key的字符串a插入到trie中
void Insert(char *a,int key)
{
int p = ;
for ( ; *a ; a ++)
{
int c = ID[*a];
if (!chd[p][c])
{
memset(chd[sz] , , sizeof(chd[sz]));
val[sz] = ;
chd[p][c] = sz ++;
}
p = chd[p][c];
}
val[p] = key;
}
//建立AC自动机,确定每个节点的权值以及状态转移
void Construct()
{
int *s = Q , *e = Q;
for (int i = ; i < CHILD_NUM ; i ++)
{
if (chd[][i])
{
fail[ chd[][i] ] = ;
*e ++ = chd[][i];
}
}
while (s != e)
{
int u = *s++;
for (int i = ; i < CHILD_NUM ; i ++)
{
int &v = chd[u][i];
if (v)
{
*e ++ = v;
fail[v] = chd[ fail[u] ][i];
//以下一行代码要根据题目所给val的含义来写
val[v] |= val[ fail[v] ];
}
else
{
v = chd[ fail[u] ][i];
}
}
}
}
} AC; int N, L;
int cost[MAXN];
bool dp[][MAX_NODE][ ( << ) + ]; int getVal( int S )
{
int res = ;
for ( int j = ; j < N; ++j )
if ( S & ( << j ) )
res += cost[j];
return res;
} int main()
{
char gene[];
AC.Initialize();
while ( scanf( "%d%d", &N, &L ) == )
{
AC.Reset();
for ( int i = ; i < N; ++i )
{
scanf( "%s%d", gene, &cost[i] );
AC.Insert( gene, << i );
}
AC.Construct(); int all = << N; memset( dp[], false, sizeof(dp[]) );
int pre = , cur = ;
dp[][][] = true;
for ( int i = ; i <= L; ++i )
{
memset( dp[cur], , sizeof(dp[cur]) );
for ( int j = ; j < AC.sz; ++j )
{
for ( int k = ; k < ; ++k )
{
int next = AC.chd[j][k];
for ( int S = ; S < all; ++S )
{
if ( dp[pre][j][S] )
dp[cur][next][ S|AC.val[next] ] = true;
}
}
}
pre ^= ;
cur ^= ;
} int ans = -;
for ( int i = ; i < all; ++i )
{
for ( int j = ; j < AC.sz; ++j )
{
if ( dp[pre][j][i] )
{
ans = max( ans, getVal(i) );
break;
}
}
} if ( ans < ) puts("No Rabbit after 2012!");
else printf( "%d\n", ans );
}
return ;
}

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

  1. HDU 4758 Walk Through Squares( AC自动机 + 状态压缩DP )

    题意:给你两个串A,B, 问一个串长为M+N且包含A和B且恰好包含M个R的字符串有多少种组合方式,所有字符串中均只含有字符L和R. dp[i][j][k][S]表示串长为i,有j个R,在自动机中的状态 ...

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

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

  3. hdu 4057(ac自动机+状态压缩dp)

    题意:容易理解... 分析:题目中给的模式串的个数最多为10个,于是想到用状态压缩dp来做,它的状态范围为1-2^9,所以最大为2^10-1,那我们可以用:dp[i][j][k]表示长度为i,在tri ...

  4. HDU 4511 (AC自动机+状态压缩DP)

    题目链接:  http://acm.hdu.edu.cn/showproblem.php?pid=4511 题目大意:从1走到N,中间可以选择性经过某些点,比如1->N,或1->2-> ...

  5. POJ 3691 (AC自动机+状态压缩DP)

    题目链接:  http://poj.org/problem?id=3691 题目大意:给定N个致病DNA片段以及一个最终DNA片段.问最终DNA片段最少修改多少个字符,使得不包含任一致病DNA. 解题 ...

  6. bzoj1195 神奇的ac自动机+状态压缩dp

    /* 难的不是ac自动机,是状态压缩dp 之前做了一两题类似题目,感觉理解的还不够透彻 */ #include<iostream> #include<cstdio> #incl ...

  7. hdu 2825(ac自动机+状态压缩dp)

    题意:容易理解... 分析:在做这道题之前我做了hdu 4057,都是同一种类型的题,因为题中给的模式串的个数最多只能为10个,所以我们就很容易想到用状态压缩来做,但是开始的时候我的代码超时了dp时我 ...

  8. 计蒜客-蒜场抽奖(AC自动机+状态压缩DP)

    题解:题意不再说了,题目很清楚的. 思路:因为N<=10,所以考虑状态压缩 AC自动机中 val[1<<i]: 表示第i个字符串.AC自动机中fail指针是指当前后缀在其他串里面所能 ...

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

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

随机推荐

  1. 头部导航悬浮,css

    .header{ position:fixed; z-index:100; left:; right:; } 如图.

  2. 日常运维管理技巧一(查看负载 W)

    日常运维管理技巧一(查看负载 W) 今天针对Linux系统管理做一个专题的记录,以后会用的几率也是很大的,只要掌握必备的基础知识,做初级系统管理员是不成问题的. 作为一个运维工程师.系统管理员,如果对 ...

  3. 理解 JavaScript 作用域(转)

    简介 JavaScript 有个特性称为作用域.尽管对于很多开发新手来说,作用域的概念不容易理解,我会尽可能地从最简单的角度向你解释它们.理解作用域能让你编写更优雅.错误更少的代码,并能帮助你实现强大 ...

  4. html编写头部,mata的含义

    <meta name="viewport" content="width=device-width, initial-scale=1.0"> con ...

  5. spring-JDBC Template

    JDBC Template概念 为简化持久化操作,spring在JDBC API之上提供JDBC Template组件 提供统一模板: 环境配置 1.创建MySQL数据库 2.搭建maven项目,并引 ...

  6. (二)、Python 基础

    Python入门 一.第一句Python 在 /home/dev/ 目录下创建 hello.py 文件,内容如下: print "hello,world" 执行 hello.py ...

  7. asp.net core-项目开发中问题汇总

    无法启动进程\Program File\dotnet\dotnet.exe.进程创建失败,出现错误:系统找不到指定的文件如下图: 解放方案:1.修改系统环境变量 2.重启电脑

  8. C语言指针篇(一)指针与指针变量

    指针 1. 什么是指针?    2. 指针可不可怕? 3. 指针好不好玩? 4. 怎么学好指针?     C语言是跟内存打交道的语言,指针就是内存地址.指针无处不在,指针并不可怕,相反,等你学到一定程 ...

  9. sed命令例子详解

    sed -e '/Patricia/h' -e '/Margot/x' datafile 包含Margot的行将被包含Patricia的行替换: sed -e /WE/{h;d;}' -e '/CT/ ...

  10. J2EE中getParameter与getAttribute以及对应的EL表达式

    摘自http://blog.csdn.net/woshixuye/article/details/8027089 getParameter ① 得到的都是String类型的.如http://name. ...