Diu 的 dp 题单
原本想写学习笔记的,但是 dp 题目太多,套路太深,我把握不住,所以我决定改成写题单。
本题单主要收录一些 dp 题目的神秘操作,当然也有一些套路比较常见,只是选一些做代表收录。
CF1626 A Random Code Problem
期望 dp,桶:开一个桶维护 表示操作 次之后共有多少个 ,对于每一个 dp 值统计答案,设 ,发现 的部分始终不变,统一统计即可。
P3736 [HAOI2016]字符合并
区间 dp 和状压 dp:设 表示区间 的串最后合并成串 的最大分数。发现因为每次合并的价值均为正数,所以能合并肯定合并,所以最后一个固定的区间 会合并成长度为 的串,直接暴力 dp 即可。
P4007 小 Y 和恐怖的奴隶主
矩阵优化,卡常:发现 很小,但是 很大,考虑直接开 维维护血量。设 表示攻击 次,有 个奴隶主血量为 , 个奴隶主血量为 , 个奴隶主血量为 的期望打掉 boss 的血量,直接从 暴力构建转移矩阵到 ,复杂度 。多组数据时,一个优化是把 的次幂的矩阵预处理出来,然后每次二进制拆分,用一个行矩阵(或列矩阵)乘上需要的,优化到 。还需卡常,在矩乘时用一个 __int128
做中间量,最后统一取模。
P4590 [TJOI2018]游园会
状压,dp 套 dp:字符串计数,考虑 表示前 个字符,满足什么状态的方案数。对于 的限制,我们可以考虑加一位 表示和 的匹配程度。对于最长公共子序列,我们可以考虑还原在 dp 求最长公共子序列的过程。如果把兑奖串看做已知,那么设 表示第一个串前 个字符,第二个串的前 个字符匹配了多少个,那么 。发现 的转移只和 有关。我们可以考虑用一个状态 存储一个 ,然后每次转移暴力解压出来,更新完之后再压缩回去。但是这样做状态数很多,我们可以发现 ,所以我们可以把 差分起来,再状压。
CF1648C Tyler and Strings
计数 dp,数据结构优化:我们从小到大枚举每一位 表示 和 前 位相同的情况,更新桶,表示当前可用点。如果第 位使得 字典序更小,那么后面的可以乱填。那么假设 是桶,对于一个 ,我们的方案数是 ,然而每次枚举一位只会改变一个 的值,所以可以用数据结构维护这个过程。具体地,可用线段树,也可用树状数组维护前缀和。
SOJ 4. Journey
期望树形 dp,容斥,卡常
SOJ 5. Festival
期望计数 dp
SOJ 6. Random
期望 dp,矩阵优化,cdq
以上三题做法太神仙,笔者太弱,无法很好总结,另见 solution。
SOJ 1.博弈
博弈论,DAG 图上 dp,背包 dp:可以发现每个点有无棋子对答案贡献互相独立,可以用一次 dp 解决。可以先设 表示节点 可以使得当前先手领先多少个点,对于一个可以转移的 ,如果 同色,那么 ,否则 , 在所有状态中取 ,特殊地,持棋者可以一步不走,所以 也可以为 。一遍 dp 更新完 之后,我们按颜色分开,即一部分是对 A
有正贡献,一部分是负贡献。那么对两者分别跑背包,然后统计即可。
P6803 [CEOI2020]星际迷航
博弈论,树形 dp,矩阵优化:模拟赛时奇妙 65 分,至今不知原因。
我们发现除了第一棵树,其他树上节点我们只需要知道以它为根节点的情况,可以考虑换根 dp。我们发现一个一个必胜点向后面接了一条边什么事都无,而一个必败点往后借一条边,如果连的是必胜也无用,否则会改变某一些点的 dp 值。我们可以考虑矩阵优化。最后再做一次树形 dp 统计答案即可,细节极多。
CF1500F Cupboards Jumps
构造,普通 dp,set 的神秘操作:我们发现题目和 的值无关,只和 的差分有关,所以我们考虑对差分 进行 dp,直接设 表示前 个数中 是否可行。然后我们可以发现 dp 数组的转移情况只有:以某个点为中心翻转,整个值域覆盖,删除或加入单点。我们发现单点的值不多,可以用 set 维护,对于区间翻转操作,可以用两个便捷维护,用两个值维护区间是否翻转,即区间便宜的值。每次翻转操作我们对整个区间进行翻转,这样单次复杂度 。
P6773 [NOI2020] 命运
计数树形 dp,线段树合并维护:因为所给的链都是返祖链(两个端点有祖先-后代关系的链),所以我们可以设 表示子树 内,需要在深度为 的祖先下面之前选一个点的方案数。如果不需要再选择,那么 。然后我们考虑转移,对于 的一个儿子 ,我们可以考虑类似树上背包的转移,假设 表示节点 的深度,其中根节点深度为 ,那么:
前面一个 是求当前点选择的情况,后面两个是求不选择的情况。我们发现这个东西维护一个前缀和就能够快速求出。我们可以考虑线段树合并,维护区间 dp 值的和。然后合并的时候可以维护两个全局变量表示前缀 的和和后缀 的和。总体比较好写。
类似题目推荐:P5298 [PKUWC2018]Minimax,期望树形 dp,同样是用线段树合并维护。
P6669 [清华集训2016] 组合数问题
数位 dp,组合数:其实就是 的个数。然后用 Lucas
定理拆开:。我们发现满足条件必须要这些组合数中必须要有某个 ,因为每个 。所以要有 。我们发现问题可以转化成两个 进制数 ,两个有上限,要求 ,某一位 ,然后跑数位 dp 就行了。
如果不会 Lucas
定理,可以看我的 数论家族学习笔记。
P5468 [NOI2019] 回家路线
本题有 加强版,注意两者数据范围不同。
斜率优化,图上 dp:发现转移花里胡哨,我们如果按每个点进行 dp 的话,发现光转移的复杂度就是 的,根本吃不消。我们可以考虑把航班设到状态,然后把时间(航班时间)和空间(出发点和终点)放到转移条件。然后我们把转移的式子拆开,发现可以斜率优化,现在开始考虑转移条件。对于每个航班,更新时从出发点更新,完了之后插入到终点,这样就处理好了空间限制。对于时间限制,我们可以用类似扫描线的思路,把每个航班拆成两个,按时间排序。第一次扫到就更新 dp 值,第二次插入到单调队列里。
P3244 [HNOI2015]落忆枫音
普通 dp,计数:对于一个 DAG 上的统计,我们有一个结论:假设点 的入度是 ,那么方案数就是 ,具体就是每个点选择一个父亲。但是新加了一条边 ,可能会有环,我们要从上述答案中减去环的情况。我们假设这个环上的点为 ,大小为 ,那么我们住了这个环以外的点乱选,那么要减去的值为 。我们发现这个东西可以 dp,我们假设 表示从 到 的路径上,该式的值。容易得到 ,那么答案就是 。
SP3734 PERIODNI - Periodni
SPOJ 太奇怪了,所以直接放 luogu 链接了。
笛卡尔树,树形 dp,组合计数:我们发现,如果按照笛卡尔树的思路分割序列,对应的两个子树内是不会互相影响的。建完笛卡尔树之后,我们考虑树上背包。设 表示子树 选 个的方案数。然后随便用组合数统计一下就可以了。
SOJ 28.寄
树上 dp:我的理解是拆维。考虑一个高维 dp,设 表示子树 内,最近的关键点距离点 为 ,剩下 个点没匹配的最小贡献,这里需要统计 个没匹配的点到点 的距离。显然可以大力背包,因为 和 都和子树的 size
有关,所以能过 的。我们考虑拆维,设 表示子树 内,剩下 个点没匹配的最小贡献, 表示子树 内所有点匹配,最近关键点距离点 为 。然后 正常更新,用 来更新 , 的更新就相当于已经知道两棵子树的 ,合并它们(两子树顶点有一条权值为 的边)。假设两子树根分别为 ,那么我们可以先枚举关键点 在 ,再枚举 里面有多少个没匹配的点,让它们全部连向 ,这一步要用到 和 。同理,反过来,当关键点在 时做相同处理。更新 的时间复杂度可以考虑每两个点会在它们的 lca
被统计,所以是 ,更新 的同理。总时间复杂度 。
SOJ 30.润
ddp:先考虑朴素 dp,设 表示区间 有无进位的答案,那么如果 ,那么 ,否则 。然后考虑 ddp,写成矩阵形式,从 往前转移。注意 只和 的二进制位数有关,可以递推,但是要特判 的情况。所以查询时可以先找到从右往左的第一第二个 的位置,分别查询即可。细节非常多,不过大样例好评!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术