状压 dp 做题记录

P2704 [NOI2001] 炮兵阵地

  • 可以发现 \(M\leq 10\) ,那么考虑状压

  • 因为状态和前 2 行都有关,那么考虑状压下每两行的状态

  • \(f[i][S_1][S_2]\) ,表示当前 \(i\) 行,当前行状态为 \(S_1\) ,上一行状态为 \(S_2\) 的方案数

P1896 [SCOI2005]互不侵犯

  • 可以发现 \(N\leq 9\) ,考虑状压

  • 还是考虑压缩下每一行的状态

P1879 [USACO06NOV]Corn Fields G

  • 可以发现 \(M\leq 12\) ,考虑状压

  • 还是考虑压缩下每一行

P3052 [USACO12MAR]Cows in a Skyscraper G

  • 可以发现 \(n\leq 18\) ,考虑状压

  • \(f[S]\) 表示选这些物品的最小分组

  • 注意子集枚举的技巧 for(int S0=S;S0;S0=(S0-1)&S)

P2396 yyy loves Maths VII

  • 注意到 \(n\leq 24\) ,还是考虑状压

  • \(f[S]\) 表示走到这个状态的方案数

  • 那么对于每个方案,枚举上一个出牌的那一张牌,注意厄运数字不能转移

P2831 [NOIP2016 提高组] 愤怒的小鸟

  • 注意到小猪 \(n\leq 18\)

  • 仍然是将小猪的状态压下来,枚举子集

  • 如果子集和自己小猪的数量差是 0/1 ,那么可以直接转移

  • 如果是多个小猪,那么就需要判断这些小猪能否用一个二次函数解决

  • 时间复杂度就是 \(O(Tn2^n)\)

P2473 [SCOI2008] 奖励关

  • 可以发现这个东西不好正着推,因为有一些限制,所以考虑反着推

  • \(f[i][S]\)\(i\) 轮前,得到的物品集合为 \(S\) ,第 \(i\) 轮到第 \(n\) 轮得到的价值的期望

  • 那么枚举这一轮会得到什么物品,每个物品得到的概率是相等的,所以转移就可以了

  • 因为我们已经知道之前的状态了,所以这样转移是正确的

P3959 [NOIP2017 提高组] 宝藏

  • 其实就是对于这个图,求一个最小代价的生成树

  • 可以发现每次拓展的花费和所在的树高有关

  • \(f[S][i]\) 表示当前已经选好了集合 \(S\),树高为 \(i\) 的最小代价

  • 我们可以枚举这个集合的子集,并且满足这个子集可以拓展得到这个集合,然后通过子集转移过来

  • 具体的对于每一个新加入的点,求出到这个子集的最短距离和,然后乘上子集的树高,也就是 \(f[S][i]=\max(f[s_0][i-1]+i*dis)\)

  • 初始化就是每个点一开始做单独一个集合的代价就是 0

  • 可以发现有值的 \(f\) ,一定是至少满足这个集合是一联通的,不至于不合法

  • 但是对于这个树高不一定能达到,求出来的代价会偏大,但是其实这个是没有关系的

  • 因为最终的答案一定可以通过一个最优的形式转移过去,也就是答案其实是一定可以转移到的

  • 枚举每个集合的子集,复杂度是 \(O(3^n n^2)\)

P2150 [NOI2015] 寿司晚宴

  • 一个朴素的 dp 式子: \(dp[i][S_1][S_2]\) 表示吃完了当前的后,分别的质数集合

  • 但是因为值太大了,质数是压不下的,考虑一个经典的 trick ,根号分治

  • 对于 \(\leq \sqrt{500}\) 的质数,仍然状压,其他的质数单独考虑,每个数只会有一个大质数

  • 那么我们预处理出一个数的质数集合和大质数

  • 将所有的数按照大质数排序,这样做是为了将大质数相同的数放在一起考虑

  • 对于一段连续的大质数相同的数,这一段数要么全部给 S1 ,要么全部给 S2 ,要么谁都不要

  • 那么对于这一段可以单独用两个数组 \(f_1[S_1][S_2],f_2[S_1][S_2]\) 转移,分别表示这一段都给了 \(1,2\)

  • 那么在一段的开头,将 \(dp\) 数组赋值在 \(f_1,f_2\) ,然后用 \(f_1,f_2\)v 转移,在一段结束后,再将 \(f_1,f_2\) 赋值回 \(dp\) 数组

  • 参考代码

P2622 关灯问题II

  • 考虑对于每种灯的状态都状压下来,然后跑最短路

P3343 [ZJOI2015]地震后的幻想乡

  • 说一个最平凡的做法

  • 对于每条边的相对排名的概率是相同的,那么最暴力的做法就是全排列出每条边的排列,然后直接 Kruskal 判断到第几条边整个图能联通,假设是第 \(x\) 条,那么这条边的期望时间是 \(\frac{x}{m+1}\)

  • 那么我们可以转换成求每一种 \(\frac{x}{m+1}\) 的贡献,也就是恰好第 \(x\) 边使得图联通的概率

  • 将这个概率前缀和一下,假设为 \(P_i\) ,那么恰好为第 \(i\) 条边使得图联通的概率就是 \(P_{i}-P_{i-1}\)

  • 所以现在就是要求 \(i\) 条边使得图能联通的概率(注意没有恰好

  • 而概率可以转换成求满足条件的方案数和方案总数,方案总数比较好表示,所以就是要求方案数

  • 注意到这个 \(n\leq 10\) ,那么考虑状压,设 \(f[S][i]\) 表示 \(S\) 这个集合用 \(i\) 条边使得联通的方案数,设 \(g[S][i]\) 表示 \(S\) 这个集合用 \(i\) 条边无法联通的方案数,\(sz[S]\)\(S\) 集合涉及的边数量

  • 那么 \(f[S][i]+g[S][i]=\binom{sz[S]}{i}\),正反则难,考虑求 \(g\)

  • 对于一个集合 \(S\) 的联通情况,我们考虑随便找一个集合内的点,然后枚举这个点所在的集合,这个集合用了的边的数量

  • \(g[S][i]=\sum_{T\to S,T\neq S}\sum_{j=0}^{\min(sz[T],i)} f[T][j]\binom{sz[S]-sz[T]}{i-j}\)

  • \(g\) 求出来了,\(f\) 就可以求了

  • 那么 \(P_i=\frac{g[U][i]}{\binom{m}{i}}\)

  • \(Ans=\frac{1}{m+1}\sum_{i=1}^{m} i\times P_i\)

P5643 [PKUWC2018]随机游走

  • 题目就是要求到达一个集合期望最长的步数

  • 通过 Min-Max 转换成一个集合到一个点的最小期望步数

  • 用树上高斯消元预处理出每个集合到 \(x\) 的最小期望步数

  • 进一步的优化就是 FWT 卷一下

BZOJ2004交通路线 bus

  • 观察到这个 \(n\leq 10^9\) ,考虑矩乘

  • 那么首先要推式子,发现这个 \(P,K\) 很小,把这个东西状压一下

  • \(f[i][S]\) 表示位置 \([i,i+P-1]\) 是状态 \(S\) 的方案数

  • 考虑怎么转移

  • 这个状态一定要恰好有 \(K\) 个 1

  • 对于每个合法的状态,考虑可以转移到哪些状态

  • 对于一个新的位置,一定会有一个位置跳过去

  • 如果当前状态的首位是 1 ,那么必须是这个 1 跳过去

  • 否则的话,就选一个 1 跳过去

  • 那么系数矩阵就可以预处理出来了

一些小 trick

  • 对于数据范围小成指数级别的,那就可以考虑状压了

  • 枚举每个集合的子集的复杂度是 \(3^n\)for(int S0=S;S0;S0=(S0-1)&S)

posted @ 2022-06-04 10:04  Kzos_017  阅读(31)  评论(0编辑  收藏  举报