状压 DP 做题记录
状压 DP
状压是一种把集合映射到数字的方法,通常是二进制状压,每一位的 01 表示集合是否含有这一项。状压可以大幅度减少与集合有关的 DP 写法上的复杂性,而且用上位运算相关的技巧还可以优化复杂度,是一种常见的方法。
一般的状压是往一个集合中加入或删除一个元素进行转移,也有枚举子集、超集进行转移,这一类有可以用高维前后缀和优化,还有些可以用 FWT、子集卷积优化。
状态的设计肯定是基于题目中实际数据范围小的量,然后判断转移是添加、删除元素还是枚举子集一类。
一种很优雅的枚举子集方法:
for(int T=S;T;T=(T-1)&S){
f[T]->f[S]
}
CF11D A Simple Task
题意:求简单无向图的环数。
思路:设
trick:对于状态,可以钦定编号最小的点是关键点,减少状态量。
P5912 [POI2004] JAS
题意:求最浅的点分树深度。
思路:相当于找深度最浅的点分树。设
[APC001F] XOR Tree
题意:给一棵有
树边编号从
你可以对树执行任意次操作,每次操作选取一条链和一个非负整数
问最少需要多少次操作,使得所有边的权值都为
思路:首先边权不好处理,于是试着转成点权,即每个点的点权是与它相连的所有边权的异或和,这样每次操作一条链就是操作两个端点,于是原问题就转化成了有一些数,每次可以选择两个数异或上一个数,求使得所有数是0的最小操作次数。我们把相等的数两两配对,这样最后只会剩下不到16个数。
接着就可以直接状压,因为只有所有数异或和为 0 才能消成 0,所以对于一个状态
trick:将链操作通过异或差分为对单点的操作,然后通过减少状态量来使得可以支持状压。
P6499 [COCI2016-2017#2] Burza
思路:好题!
一开始没细想 既定的策略,然后一直以为贪心是对的,后来才发现问题。不过好在是想到了复杂度的来源:
正解:首先,每次我们肯定是选择一个深度为
因为
trick:可以通过钦定与顺序无关以更方便状压。
P9333 [JOISC 2023 Day2] Council
题意:在 JOI 市议会中,有
JOI 市议会的程序如下所示。
-
选定主席,主席将在除了主席以外的其他
名议员中选择副主席。 -
将对
项提案进行表决。除了主席和副主席以外的其他 名议员,每人对每个提案均投票支持或反对。如果大多数议员(即肯定票大于等于 )投票赞成,则议会将批准该提案。其中 表示不超过 的最大整数。
市长 K 希望议会尽可能地批准更多的提案。市长 K 收集了议员的信息并知道每个议员在每个提案上的表决结果。你需要求出在给定议员投票信息的情况下,计算每个议员作为主席时议会可以批准的提案数量的最大可能值。
思路:一开始把题意理解错了,想了一些跟状压相关的东西,但是没想出来,结果才发现题目看错了,就懒得想了。
首先,确定了一个人后对答案有影响的只有那些
我们发现,
trick:min 和 max 的灵活转化。
P9131 [USACO23FEB] Problem Setting P
题意:有
思路:好像有一车做法,甚至
有一个比较简单的做法是分成前后两部分,设
也可以类似 CDQ 分治一样先做左儿子,然后算左儿子对右儿子的贡献,然后算右儿子。
trick:折半处理可以有效降低复杂度。
[AGC016F] Games on DAG
题意:给定一个
思路:依旧不会 SG 函数。
两颗石子是互不相干的,于是可以分开考虑。假设求出了两颗石子的 SG 函数
分析一下 SG 序列的性质。如果有一个
再找特殊情况:
于是考虑状态压缩。设
P4363 [九省联考 2018] 一双木棋 chess
思路:轮廓线 DP 模版题。
发现每个状态都是从上到下每一行选了的数都是一段前缀,而且长度不增,于是考虑维护轮廓线。
如图,从左侧开始,如果上面被选了就向右走,加上 0,否则就往上走,加上 1,下图就是 1011010010:
首先求出当前是谁移动,然后枚举转移,就是从哪一行拓展一个,就可以了。
trick:轮廓线可以被描述成一个 01 串,可以基于此来状压。
P3160 [CQOI2012]局部极小值
题意:往
思路:因为所有格子里的数互不相同,所以在
trick:状压很适合和容斥一起处理。
CF79D Password
题意:有长度为 n 的 01 串和 l 个长度,每次可以将某个长度的子区间的取反,初始全是 0,求把给定的 k 个位置变成 1 的最小步数。
思路:把状压和最短路结合起来的题目好像很罕见
看到
设
我们考虑每进行一次操作是把相隔为
总复杂度
trick:区间操作差分成单点操作。
P3349 [ZJOI2016]小星星
题意:给定有
思路:考虑到求编号,我们设
我们考虑优化。首先很容易想到把标号集
trick:遇到带标号的限制,可以容斥掉这个限制。
P7519 [省选联考 2021 A/B 卷] 滚榜
题意:给出
思路:学到了一个很新的科技
我们考虑DP的状态应该与那些有关,首先是已经加入了的位置有哪些,这个是
我们考虑怎么去掉一维。我们可以发现,一旦确定了顺序,我们就可以贪心地使每次的
复杂度
trick:费用提前计算。
CF1322B Present
题意:求两两加和的异或和。
思路:因为是求异或和,可以按位考虑。对于第
CF1550E Stringforces
题意:- 设
- 定义
的价值为所有 的最小值,其中 取遍前 个小写字母。 - 现在给定一个长度为
的字符串 , 中字母要么是前 个小写字母中的某一个,要么是问号。你需要将 中的每一个问号替换成前 个小写字母中的一个,并最大化 的价值。方便起见,你只需要输出这个最大的价值即可。
思路:因为是最小值最大,于是想到二分答案。
因为字符集很小,可以考虑状压。那么状态就是如果要使
trick:要达到整体合法,可以把状态设为用什么样的集合可以覆盖多长的前缀/需要多长的前缀。
P2150 [NOI2015] 寿司晚宴
题意:有
思路:朴素的想法是状压用了的质数,但是 500 以内的质数太多了,无法状压。
发现一个数至多只有 1 个大于 22 的质因子,而小于 22 的质因子只有 8 个,可以状压,那么我们就可以单独记录大于 22 的质因子。
设
复杂度
trick:减少枚举量来状压。
P6846 [CEOI2019] Amusement Park
题意:给一张图,求所有把边反向使得图是 DAG 的方案反向的边数和。
思路:首先,可以发现一张图如果是 DAG,那么把所有边反向后仍是 DAG,于是如果翻转
设
复杂度
trick:对于点集要求是 DAG 转移时的条件:转移的子集是独立集。
[AGC012E] Camel and Oases
题意:给定
现在有一个人在沙漠中进行旅行,他初始的背包的水容积为
对于每一个
思路:首先可以发现,我们使用跳跃的次数最多只有
然后考虑状压。设
然后我们枚举第一层的连续段,枚举所有层数集合,判断是否可以覆盖全集。但是如果第一层连续段很多呢?我们发现,如果多于
trick:同样是把覆盖全集转成覆盖前后缀。
CF1463F Max Correct Set
题意:规定一组正整数
-
-
如果
并且 ,那么 并且
对于给定的数值
思路:首先注意到
考虑状压。我们设
P3290 [SCOI2016] 围棋
题意:对于一个模板,只要棋盘中有某个窗口与其完全匹配,我们称这个模板是被激活的,否则称这个模板没有被激活。
考虑一个
我们希望知道,对于每个模板,有多少种棋盘可以激活它。强调:模板一定是两行的。
思路:首先容斥一步,用所有情况减去一次都不匹配的情况。
然后考虑轮廓线状压 DP。我们枚举当前行匹配到了模版第二行的哪里,轮廓线存上一行每个位置是否和模版第一行匹配,于是状态就是
trick:对于匹配的问题,通常用 kmp。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!