状压 dp 做题记录
-
可以发现 \(M\leq 10\) ,那么考虑状压
-
因为状态和前 2 行都有关,那么考虑状压下每两行的状态
-
设 \(f[i][S_1][S_2]\) ,表示当前 \(i\) 行,当前行状态为 \(S_1\) ,上一行状态为 \(S_2\) 的方案数
-
可以发现 \(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)
-
注意到 \(n\leq 24\) ,还是考虑状压
-
设 \(f[S]\) 表示走到这个状态的方案数
-
那么对于每个方案,枚举上一个出牌的那一张牌,注意厄运数字不能转移
-
注意到小猪 \(n\leq 18\)
-
仍然是将小猪的状态压下来,枚举子集
-
如果子集和自己小猪的数量差是 0/1 ,那么可以直接转移
-
如果是多个小猪,那么就需要判断这些小猪能否用一个二次函数解决
-
时间复杂度就是 \(O(Tn2^n)\)
-
可以发现这个东西不好正着推,因为有一些限制,所以考虑反着推
-
设 \(f[i][S]\) 为 \(i\) 轮前,得到的物品集合为 \(S\) ,第 \(i\) 轮到第 \(n\) 轮得到的价值的期望
-
那么枚举这一轮会得到什么物品,每个物品得到的概率是相等的,所以转移就可以了
-
因为我们已经知道之前的状态了,所以这样转移是正确的
-
其实就是对于这个图,求一个最小代价的生成树
-
可以发现每次拓展的花费和所在的树高有关
-
设 \(f[S][i]\) 表示当前已经选好了集合 \(S\),树高为 \(i\) 的最小代价
-
我们可以枚举这个集合的子集,并且满足这个子集可以拓展得到这个集合,然后通过子集转移过来
-
具体的对于每一个新加入的点,求出到这个子集的最短距离和,然后乘上子集的树高,也就是 \(f[S][i]=\max(f[s_0][i-1]+i*dis)\)
-
初始化就是每个点一开始做单独一个集合的代价就是 0
-
可以发现有值的 \(f\) ,一定是至少满足这个集合是一联通的,不至于不合法
-
但是对于这个树高不一定能达到,求出来的代价会偏大,但是其实这个是没有关系的
-
因为最终的答案一定可以通过一个最优的形式转移过去,也就是答案其实是一定可以转移到的
-
枚举每个集合的子集,复杂度是 \(O(3^n n^2)\)
-
一个朴素的 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\) 数组
- 考虑对于每种灯的状态都状压下来,然后跑最短路
-
说一个最平凡的做法
-
对于每条边的相对排名的概率是相同的,那么最暴力的做法就是全排列出每条边的排列,然后直接 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\)
-
题目就是要求到达一个集合期望最长的步数
-
通过 Min-Max 转换成一个集合到一个点的最小期望步数
-
用树上高斯消元预处理出每个集合到 \(x\) 的最小期望步数
-
进一步的优化就是 FWT 卷一下
-
观察到这个 \(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)