【题解】CF1856E2 背包 复杂度分析 压位
此处假设读者已经通过 E1,会 地解决本问题:
在每一个点时做的操作就是“把儿子大小构成的数集合分成差尽可能小的两部分”。
接下来来解决 E2:
首先一个观察就是单个问题“把儿子大小构成的数集合分成差尽可能小的两部分”是一个 的背包可行性问题。没有 的做法,常见的做法有三种:
- 所以 的种类只有 种,直接做余数分类 。
- 将每种 的个数进行二进制拆分,然后
bitset
压位复杂度 ,常数很小。 - 多项式卷积,NTT 或 FFT 合并,,常数大。
令上方解决规模 单层问题的复杂度为 。
如果每层都解决一次这样的问题,复杂度仍然是 的,这最坏仍然可以达到 。
因为树 的构成是具有特殊性的,解决完这个问题后子问题的规模和这个问题的构成是密切相关的 (这显然弱于解决任意 次上面问题)。
又因为我们只是想尽可能平均分两个集合,所以当重儿子的 大于其它儿子的 之和时,一定会选择将重儿子放在一个集合中,所有轻儿子放在另一集合,所以只有重儿子的 小于目前 的一半时我们才会进行背包,而如果重儿子的 小于目前 的一半,然后所有子问题的规模都变成了原来的一半,所以最坏复杂度为 。
带入具体复杂度分析都是简单的主定理:
如果 ,。
如果 ,。
如果 ,。
第三种理论最优,但是在题目数据范围下使用第二种,最坏耗时约 300ms,可以轻松通过。
一个实现上的小问题是需要使用动态大小的 bitset
,可以选择手写或者提前开好所有大小为 的 bitset
,然后使用的时候选择最小的可用的。
upd:可以证明更优秀的复杂度:直接进行二进制拆分的复杂度其实是 的,具体的复杂度分析见 这里 或者 这里,感谢 @王熙文 的指出,Orz。
本文已经结束了。本文作者:ღꦿ࿐(DeepSea),转载请注明原文链接:https://www.cnblogs.com/Dreamerkk/p/17970905,谢谢你的阅读或转载!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步