背包计数问题的多项式优化

此优化针对以下计数问题:

n 件物品,背包容量为 m,第 i 件物品体积为 ai,求装满的方案数。(01背包)

n 种物品,背包容量为 m,第 i 件物品体积为 ai,数量无限,求装满的方案数。(完全背包)

n 种物品,背包容量为 m,第 i 件物品体积为 ai,数量为 bi,求装满的方案数。(多重背包)

(1n1e5,1m1e5,1ai,bi1e5)

不止求装满的方案数,用多项式优化后求装任意体积都是 O(mlogm)


01背包计数

首先来看计数01背包的生成函数:

第 i 个物品:Gi(x)=1+xai

x0 项表示不选,xai 表示选,占体积为 ai

那么刚好装满容量为 k 的背包的方案数为:G(x)[xk]=i=1nGi(x)[xk]=(1+xa1)(1+xa2)...(1+xan)[xk]

这个式子看起来很好求,和我们之前遇到的另一个式子很像:(x+a1)(x+a2)...(x+an),这个式子就可以用分治NTT来求。

但是上面的式子次数太高了,如果用分治NTT来做,分治的最底层就已经爆炸了。

我们用一个小技巧,这种连乘的算式先取个对数 ln,就可以变成相加的形式,求和之后再 exp 回去就是原式:

G(x)=exp(ln(1+xa1)+ln(1+xa2)+...+ln(1+xan))

每个物品的式子都求一遍 ln 再挨个相加,这个复杂度仍然是平方的。

但是我们发现 G(x) 的每一个因式都只有两项,这个式子可以直接套用麦克劳林公式手算:ln(1+x)=xx22+x33x44+...+(1)nxn+1n+1

x 换成 xaln(1+xa)=xax2a2+x3a3x4a4+...+(1)nx(n+1)an+1

我们发现在总容量为 m 的限制下,一个体积为 a 的物品式子中有用的项只有 ma 个,其余项为0。

我们记录每种体积的物品有几个,那么每一个不同的 a 只会算一次,ma 的复杂度是调和级数的 mlogm。于是我们就解决了这个问题。


完全背包计数

洛谷有个板子题:P4389 付公主的背包,想要代码的可以看这题的题解。


和01背包原理一样,将生成函数先取对数,相加后再 exp 回去。

只是现在每种物品有无限个,因此生成函数式子稍有不同:

Gi(x)=1+xai+x2ai+...+xnai+...

Gi(x)=j=0xj·ai

Gi(x)=11xai

至于这个式子怎么转化的,那就是生成函数的基础了。

我们将这些式子取对数再相加:

ln(Gi(x))=ln(11xai)=ln(1xai)=xai+x2ai2+x3ai3+x4ai4+...+x(n+1)an+1

所以几乎和01背包的式子一样。

多重背包计数

和前者一样,也是只有生成函数式子有不同。

第 i 种物品有 bi 个,因此生成函数有 bi+1 项:

Gi(x)=1+xai+x2ai+...+xbiai

Gi(x)=1xbiai1xai

取对数后分母取负,就和完全背包的式子形式一样了,注意分子在调和级数去重时要按照 a*b 的值。


__EOF__

本文作者枫叶晴
本文链接https://www.cnblogs.com/maple276/p/18342090.html
关于博主:菜菜菜
版权声明:呃呃呃
声援博主:呐呐呐
posted @   maple276  阅读(98)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示