揹包計數問題的多項式最佳化

maple276發表於2024-08-04

此最佳化針對以下計數問題:

n 件物品,揹包容量為 m,第 i 件物品體積為 \(a_i\),求裝滿的方案數。(01揹包)

n 種物品,揹包容量為 m,第 i 件物品體積為 \(a_i\),數量無限,求裝滿的方案數。(完全揹包)

n 種物品,揹包容量為 m,第 i 件物品體積為 \(a_i\),數量為 \(b_i\),求裝滿的方案數。(多重揹包)

\((1\le n\le1e5, 1\le m\le1e5, 1\le a_i,b_i \le 1e5)\)

不止求裝滿的方案數,用多項式最佳化後求裝任意體積都是 \(O(mlogm)\)


01揹包計數

首先來看計數01揹包的生成函式:

第 i 個物品:\(G_i(x) = 1+x^{a_i}\)

\(x^0\) 項表示不選,\(x^{a_i}\) 表示選,佔體積為 \(a_i\)

那麼剛好裝滿容量為 k 的揹包的方案數為:\(G(x)[x^k]=\prod\limits_{i=1}^nG_i(x)[x^k]=(1+x^{a_1})(1+x^{a_2})...(1+x^{a_n})[x^k]\)

這個式子看起來很好求,和我們之前遇到的另一個式子很像:\((x+a_1)(x+a_2)...(x+{a_n})\),這個式子就可以用分治NTT來求。

但是上面的式子次數太高了,如果用分治NTT來做,分治的最底層就已經爆炸了。

我們用一個小技巧,這種連乘的算式先取個對數 \(ln\),就可以變成相加的形式,求和之後再 \(exp\) 回去就是原式:

\(G(x)=exp(ln(1+x^{a_1})+ln(1+x^{a_2})+...+ln(1+x^{a_n}))\)

每個物品的式子都求一遍 \(ln\) 再挨個相加,這個複雜度仍然是平方的。

但是我們發現 \(G(x)\) 的每一個因式都只有兩項,這個式子可以直接套用麥克勞林公式手算:\(ln(1+x)=x-\frac{x^2}{2}+\frac{x^3}{3}-\frac{x^4}{4}+...+(-1)^n\frac{x^{n+1}}{n+1}\)

\(x\) 換成 \(x^a\)\(ln(1+x^a)=x^a-\frac{x^{2a}}{2}+\frac{x^{3a}}{3}-\frac{x^{4a}}{4}+...+(-1)^n\frac{x^{(n+1)a}}{n+1}\)

我們發現在總容量為 m 的限制下,一個體積為 a 的物品式子中有用的項只有 \(\frac ma\) 個,其餘項為0。

我們記錄每種體積的物品有幾個,那麼每一個不同的 a 只會算一次,\(\sum\frac m a\) 的複雜度是調和級數的 \(mlogm\)。於是我們就解決了這個問題。


完全揹包計數

洛谷有個板子題:P4389 付公主的揹包,想要程式碼的可以看這題的題解。


和01揹包原理一樣,將生成函式先取對數,相加後再 \(exp\) 回去。

只是現在每種物品有無限個,因此生成函式式子稍有不同:

\(G_i(x)=1+x^{a_i}+x^{2a_i}+...+x^{na_i}+...\)

\(G_i(x)=\sum\limits_{j=0}^{\infty}x^{j·a_i}\)

\(G_i(x)=\frac{1}{1-x^{a_i}}\)

至於這個式子怎麼轉化的,那就是生成函式的基礎了。

我們將這些式子取對數再相加:

\(ln(G_i(x))=ln(\frac{1}{1-x^{a_i}})=-ln(1-x^{a_i})=x^{a_i}+\frac{x^{2{a_i}}}{2}+\frac{x^{3{a_i}}}{3}+\frac{x^{4{a_i}}}{4}+...+\frac{x^{(n+1)a}}{n+1}\)

所以幾乎和01揹包的式子一樣。

多重揹包計數

和前者一樣,也是隻有生成函式式子有不同。

第 i 種物品有 \(b_i\) 個,因此生成函式有 \(b_i+1\) 項:

\(G_i(x)=1+x^{a_i}+x^{2a_i}+...+x^{b_ia_i}\)

\(G_i(x)=\frac{1-x^{b_ia_i}}{1-x^{a_i}}\)

取對數後分母取負,就和完全揹包的式子形式一樣了,注意分子在調和級數去重時要按照 a*b 的值。

相關文章