核心:在于状态转移方程的状态只有0和1。可以将转移优化成位运算。
一.NC32C简单瞎搞题
传送门:https://ac.nowcoder.com/acm/contest/132/C?&headNav=www
题目思路:
,类似于:分组背包,每组必选的dp。那么朴素复杂度为:
发现dp其实上是一个bool数组,我们将其代替成bitset.然后对于一个确定的xi. 它对背包容量的转移就是位运算的左移.再开一个滚动数组直接dp即可。
二.AGC020-C --子集和数组的中位数
传送门:https://atcoder.jp/contests/agc020/tasks/agc020_c
题目大意:给你一个序列,他的子集的和有 2^n - 1 个。对它们排序以后问中位数是多少?(一定是奇数)
题目思路:
首先显然一点,这是一个01背包,我们需要dp它.
用bitset优化为:
接下来,思考如何得到中位数:
三.HDU5890 -- 01背包 + 暴力预处理
题目大意: 给你一个n(<=50)长度的序列,Q(Q<=1e5)次询问你去掉x ,y,z三个数后是否能够选出恰好10个数构成87?
题目思路:
关注到n很小,可以暴力预处理。令 f[x][y][z]代表 题目的答案。对于每一个x , y , z暴力跑一次01背包.
用bitset优化即可.
优化点:
1.bitset优化
2.输入输出优化
3.排列组合优化: 对于 (i,j,k)的全排列,本质答案是一样的.所以循环变量 i , j , k 从它们前一个变量开始。然后统一赋值即可。 快6倍
四.bzoj3687 求子集和 的 异或和 -- 01背包
n <= 2000 , sum(a) <= 1e6
题目思路:
朴素思路是:发现总和很小。用dp[i]代表i能被构造出多少次。考虑到最后进行的是异或和。所以dp[i]只需要存储0
或者 1. 所以上bitset优化。 转移方程为:
五.优化Floyd传递闭包
思路: 当 n >= 1000 时,我们用bitset优化传递闭包的最内层循环.如下图所示:
当我们发现有一个点 i 与 插点 k 有连边时,设k的出点集合为S,那么所有属于S的点都能够从i到达。
所以 i本轮松弛的结果是: