【题解】CF1856E2 背包 复杂度分析 压位
此处假设读者已经通过 E1,会 $O(n^2)$ 地解决本问题:
在每一个点时做的操作就是“把儿子大小构成的数集合分成差尽可能小的两部分”。
接下来来解决 E2:
首先一个观察就是单个问题“把儿子大小构成的数集合分成差尽可能小的两部分”是一个 $\sum siz_i \leq n$ 的背包可行性问题。没有 $O(n\log n)$ 的做法,常见的做法有三种:
- $\sum siz_i \leq n$ 所以 $siz_i $ 的种类只有 $\sqrt n$ 种,直接做余数分类 $O(n\sqrt n)$。
- 将每种 $siz_i$ 的个数进行二进制拆分,然后
bitset
压位复杂度 $O(\dfrac{n\sqrt n \log n} w)$,常数很小。 - 多项式卷积,NTT 或 FFT 合并,$O(n\log^2n)$,常数大。
令上方解决规模 $n$ 单层问题的复杂度为 $C(n)$。
如果每层都解决一次这样的问题,复杂度仍然是 $\sum C(siz_i)$ 的,这最坏仍然可以达到 $O(n^2)$。
因为树 $siz$ 的构成是具有特殊性的,解决完这个问题后子问题的规模和这个问题的构成是密切相关的 (这显然弱于解决任意 $n$ 次上面问题)。
又因为我们只是想尽可能平均分两个集合,所以当重儿子的 $siz$ 大于其它儿子的 $siz$ 之和时,一定会选择将重儿子放在一个集合中,所有轻儿子放在另一集合,所以只有重儿子的 $siz$ 小于目前 $siz$ 的一半时我们才会进行背包,而如果重儿子的 $siz$ 小于目前 $siz$ 的一半,然后所有子问题的规模都变成了原来的一半,所以最坏复杂度为 $T(n)=2T(n/2)+C(n)$。
带入具体复杂度分析都是简单的主定理:
如果 $C(n)=O(n\sqrt n)$,$T(n)=2 T(n/2)+O(n\sqrt n)=O(n\sqrt n)$。
如果 $C(n)=O(\dfrac{n\sqrt n \log n} w)$,$T(n)=2 T(n/2)+O(\dfrac{n\sqrt n \log n} w)=O(\dfrac{n\sqrt n \log n} w)$。
如果 $C(n)=O(n \log^2 n)$,$T(n)=2 T(n/2)+O(n\log^2 n)=O(n\log^3n)$。
第三种理论最优,但是在题目数据范围下使用第二种,最坏耗时约 300ms,可以轻松通过。
一个实现上的小问题是需要使用动态大小的 bitset
,可以选择手写或者提前开好所有大小为 $2^k$ 的 bitset
,然后使用的时候选择最小的可用的。
upd:可以证明更优秀的复杂度:直接进行二进制拆分的复杂度其实是 $C(n)=T(n)=O(\dfrac{n\sqrt n} {w})$ 的,具体的复杂度分析见 这里 或者 这里,感谢 @王熙文 的指出,Orz。
本文已经结束了。本文作者:ღꦿ࿐(DeepSea),转载请注明原文链接:https://www.cnblogs.com/Dreamerkk/p/17970905,谢谢你的阅读或转载!