ZOJ 3228 Searching the String

AC自动机吼题 虽然是很常规的模式串与匹配串的匹配计数问题,但它稍微给了一个新花样和一些坑。 写完这题,我当时就很感慨,如果我能在多校之前写过这题就好了…… 题意: 先给你一个匹配串,再给你很多模式串,模式串前都有标号。标号为 0 表示计数可重叠,标号为 1 表示计数不可重叠。 思路: 写不来呀………… 看了题解,kuangbin只说了一句,加一个数组维护一下就好了…………这特么怎么维护………… 看了代码大致能理解,开了一个 last 数组记录每个位置上一次被匹配时的位置。 如果匹配串的位置与AC自动机上的相应位置的上一匹配位置差距为这个模式串的长度以上,说明可以匹配。 特别想要详细说,但又觉得没有什么好说的,所谓大道至简,原理真的很简单。 AC Code #include #include #include #include using namespace std; const int max_n = 6e5 + 10; const int max_

HDU 2296 Ring

AC自动机+带权字符串DP 题目本身不是很难,但在处理上有点繁琐。 题意: 给你很多模式串,每个模式串都有一个权值,再给你一个限制长度,要你在限制长度内找出最短的字符串,使得权值和最大。若有多个结果,输出字典序最小的。 思路: 连AC自动机上的最短路都有了,加个权值也不是什么奇怪的事情。 这个加了权值有点像…………背包??不是么?? 想象不到的话将背包的物品替换成一个字符试试。 但是实际上都是我瞎猜罢了,我并没有按照背包的写法去写,还是很常规的按照节点和状态添加字符,到下一节点的下一状态。 稍微繁琐一点的就是要输出字符串,但所幸数据比较小,三维空间存的下。 #include #include #include #include using namespace std; const int inf = 0x3f3f3f3f; const int max_n = 100 * 20; const int max_c = 26; const int

POJ 1699 Best Sequence

AC自动机+spfa最短路 啊啊,明明AC自动机还有最后一题,今晚怕是写不完了,今天写的还有两道没写题解。 最后一道AC自动机与这一题有相似之处,是这一题的强力加强版本。 先把这题给解决了 题意: 给你很多碱基串,不同碱基串在前后缀相同的条件下可以重叠,要你求出最短的碱基串,包含所有给定串。 思路: AC自动机上状压SPFA,也可考虑TSP的模型。 还是属于比较基础的,连我都可以不看题解写出来的题目。 #include #include #include #include using namespace std; const int max_n = 250; const int max_c = 4; int key[130]; struct Aho { int next[max_n][max_c], fail[max_n]

HDU 3341 Lost's revenge

AC自动机 + 变进制状压DP 看题目的 discuss 都说会卡数据,但我还是 1500ms A了。虽然变进制的思路并不是我的…… 最近有点懒得写博客了呀 题意: 还是基因碱基对背景。 给你几个模式串,再给你一个匹配串,允许你对匹配串重新排列,要求重新排列后跟模式串匹配的最大数量。 思路: 如果再加个权值,那就是DP套DP了,(误…… 本质上还是一个计数DP,考虑状压,但是给定的匹配串长度上限为 40 ,如果开一个状态+节点的 5维数组,会炸内存。 考虑到将节点的 4 维压缩,因为 40 的实际状态数最多是 4 个碱基数量相同的时候。 也就是( 10 \times 10 \times 10 \times 10 ),内存与复杂度均可以承受。 AC Code #include #include #include

HDU 4899 Hero meet devil

训练赛的DP套DP,关于DP套DP,以前记得好像做过一道。题目本身十分巧妙,但貌似不是很多。可能不是很好出题吧。 所谓DP套DP,就是我DP所需的状态也需要额外的DP求出来。简单说,就是我需要DP两次,在第一次的DP结果上再DP一次。 题意: 给你一个DNA序列,再给你一个固定长度,问你在这个长度下的所有序列中,与给定的DNA序列的LCS分别为( [0,len(DNA)] )的序列数量。 思路: 因为数据很小,我们可以考虑用状压做。 对于当前长度的一个最优状态,如果增加一个字符,它的下一个状态就需要加上当前状态的序列数量。 这是一个非常常见的计数DP。 但是已知当前状态,无法直接得出下一个状态,而这个就是我们需要嵌套在内的DP了。 我们枚举每一个状态,在枚举每一个字符,使其插入当前状态,再转移它的LCS,最后再统计一下就可以了。 而统计方法是如果当前位置的LCS与前一位置的LCS不同,则说明这个位置与LCS的DNA序列匹配。 虽然我说的很简洁,但是我当时也是想了好长时间…… AC Code #include usi

HDU 4628 Pieces

CLS的状压DP系列…… 然而实际上也算是一道简单题,但是我并没有立刻写出来。 不知道为什么,每次我尝试这用已知最优状态去推其他状态都是错的…… 然而用当前状态之前的状态来推当前状态却是对的。 顺便学习了一个,二进制子集的枚举方法。for ( int sta = state ; sta ; sta = (sta - 1) & state ) 学了这么久状压居然连这个都知道真是醉了…… 题意: 给你一个字符串,每次只能取走一个回文串,问最少取几次。 思路: 先预处理出所有状态是否为回文串,并使得 这个状态取值为 1 。 枚举每个状态,再枚举它的所有子集。 状态转移方程 为 dp[sta] = min(dp[sta], dp[sta ^ s] + dp[s] ) AC Code #include #define each(i, n) for

POJ 3728 The merchant

LCA 好题! 这道题我暂时只知道用Tarjan的解法。 Tarjan解法完美地运用了Tarjan的核心原理与性质: 深度优先搜索时的向下局部性。自己乱取得,蛤蛤蛤 题意: 给你一棵树,每个节点有一个权值。给你很多个询问,每个询问两个点。要你在给定点的树链上找到有序的最大差值。 思路: 首先考虑分治。设树链 u -> lca -> v 答案无非只有三种情况: 1. u -> lca 的最大差值 2. lca -> v 的最大差值 3. lca -> v 的最大值 – u -> lca 的最小值 考虑dp维护这四个值。 因为运用Tarjan算法的时候,基于dfs,在你的眼里,当前节点就是向下整棵树的根节点,你完全不会去考虑往上的节点。 所以你现在使用的四个值,刚好是你当前节点的孩子节点的最优值。 基于这个事实,…

POJ 2449 Remmarguts' Date

K短路裸题。 这里的K短路是基于每个点只能访问一次,也就是说这个K短路必须是一条链。 再换句话说,这个K短路的K是有限制的,如果超过了这个限制,就输出 -1 。 这是和之前多校的次短路不一样的地方。 简单说一下K短路的解决思路: 首先我们应该认识到,最最简单的最短路算法是基于 bfs 改进而来,我们用 bfs 的思路继续拓展,在第一次到达终点后并不停止,而是继续 bfs 搜索,直到第K次到达终点,就是我们要求的答案。 当然,单纯的 bfs 是瞎 jb 搜,堆优化的spfa效率良好,但我们可以更进一步优化。 K短路于此之上还用了 A* 优化,先对反图 最短路遍历一遍,在正图遍历的时候,除了对起点 src 到当前距离 堆优化以外,还对当前距离进行答案估计,并将其优先级先于距离。 仔细想一想,其实很显然,不过为什么最短路不用 A* 优化呢? 因为有处理估值函数的时间,最短路都已经求完了。…