多重背包&树上背包小结

多重背包&树上背包

多重背包

\(n\) 种物品,每种物品有 \(s_i\) 个,价值为 \(v_i\) ,体积为 \(w_i\) ,背包容量为 \(V\) ,问最大价值

二进制拆分

\(s\) 进行二进制拆分,然后就是01背包的过程,\(O(nV\log V)\)

可以用bitset优化

单调队列

对于每个物品,先枚举\(k=0\sim w_i-1\),然后枚举余数为k的数,这个过程是 \(O(V)\)

然后我们发现对于一个k,进行的是内部转移,于是就维护一个单调队列即可

时间复杂度 \(O(nV)\)

CF1856E2 PermuTree (hard version)

题目描述

给定一棵以 \(1\) 为根的有根树,你需要给出一个 \(1\)\(n\) 的排列 \(a\),最大化二元组 \((u,v)\) 的数量,满足 \(a_u < a_{\rm {lca(u,v)}} < a_v\),输出这个最大值。(\(2 \leq n \leq 10^6\)

solution

可以考虑在lca处算答案,然后贪心,把儿子分成两个尽量相等的部分

于是就对儿子的子树大小进行背包,\(O(n^2)\)

然后我们发现因为一次计算的子树大小和为n,那么最多有 \(\sqrt n\) 种值,然后跑多重背包即可

注意,如果用二进制拆分,其实也没有log,但是有一个实现细节:我们把进行二进制拆分后的01物品放进桶里,然后一个桶里若有超过两个,就可以等价于二进制的进位,可以证明是物品时 \(\sqrt n\) 级别的。

然后还有个细节,用bitset要动态定义长度,所以可能需要手打

树上背包

树形背包总结 - lnzwz - 博客园 (cnblogs.com)

2023.10.11联考T4

题目描述

给定一棵 \(n\)个节点、以 \(1\) 为根的树。对于每一条边,可以选择保留或不保留。
定义一个方案的权值是:只看保留的边时,形成的各个连通块大小之积的 \(k\) 次方。试计算\(2^{n-1}\) 种方案的权值之和。

solution

计数好题

首先考虑暴力,设\(g_{i,j}\)表示以i为根的子树,i所在的联通块大小为j的代价,j=0时表示断掉i的父亲那条边,然后为了方便转移,我们i所在连通块的代价先不算,每次更新完一棵子树,再进行更新\(g_{i,0}+=\sum g_{i,j}\times j^k\)

然后我们发现可以背包转移,时空复杂度\(O(n^2)\)

想到这里发现根本无法优化,于是就需要一点经验,发现\(k\le100\)

\(f_{i,j}=\sum_{s=0}^{siz_i}(^s_j)f_{i,s}\),就是以i为根的子树,i所在的联通块贡献\((^s_j)\)的代价,我们发现,j的范围被缩减成k,然后根据第二类斯特林数的公式(普通幂转下降幂),\(s^k=\sum_{i=1}^ks2(k,i)i!(^s_i)\),然后令\(ans_i\)为该点断掉父亲的答案,\(ans_i=\sum_{j=1}^ks2(k,j)j!f_{i,j}\)

发现了可以计算答案,那么如何转移呢?

考虑状态的组合意义,在连通块中取了j个点,由于子树中的情况互不影响,可以用乘法原理,于是又可以背包转移,注意ans要当作大小为0的物品转移

然后如果我们把背包大小定为\(min(k,siz_i)\),时间复杂度为\(O(nk)\)

2023.12.24联考T1

题目大意

给定一棵树,每个节点有个01权值,一棵树的贡献定义为满足 \(x\)\(y\) 的祖先,且\(s_x=1,s_y=0\)\((x,y)\) 的数量

现在可以反转k个权值,问最小贡献。对于 \(k=0\sim n\) 都输出答案

solution

首先考虑如果要把1改成0,那么要求它的子树一定都为1,否则不如改子树

0改成1同理,要求它到根都为0

所以可以考虑一个朴素的dp,设\(f_{i,j,k}\)表示节点i的子树,用了j个反转,下面有k个0,背包转移\(O(n^3)\)

在根据上面的结论,设\(f_{i,j,0/1/2}\)表示节点i的子树,用了j个反转,子树一定都为1/它到根都为0/不确定

posted @ 2024-06-20 16:19  zhy_learn  阅读(2)  评论(0编辑  收藏  举报