多重集組合數問題

2021-07-31 20:47:15 字數 1461 閱讀 8279

參考

題目: 有n種物品, 第i種物品有a個. 不同種類的物品可以互相區分, 但相同種類的無法區分.

從這些物品中取出m個, 有多少種取法? 求出數模m的餘數.

例如: 有n=3種物品, 每種a=個, 取出m=3個, 取法result=6(0+0+3, 0+1+2, 0+2+1, 1+0+2, 1+1+1, 1+2+0).

dp[i][j]:前i種數,長度為j的個數

dp[i][j]=dp[i-1][j-k](0<=k<=min(j,m[i])):前i-1種數拿了j-k個,也就是假設第i種數拿了k個;

時間複雜度為o(n*m*m)

#include 

#include

#include

#include

#include

using

namespace

std;

const

int maxn =105;

int a[maxn];

int dp[maxn][maxn];

int main()

}printf("%d\n",dp[n][m]);

return

0;}

時間複雜度還是太高了,我們化簡一下

我們可以發現,把右邊求和式展開

分兩種情況:

情況1:j<=x[i] (即j-1< x[i])

右邊展開得到的是dp[i-1][0] dp[i-1][1] dp[i-1][2]….dp[i-1][j] 、 把最後一項拿出來,剩下的j-1項求和,是dp[i][j-1];

也就是 dp[i][j]=dp[i][j-1]+dp[i-1][j];

情況 2: j>x[i]

右邊展開得到的是dp[i-1][j-x[i]] dp[i-1][j-x[i]+1] dp[i-1][j-x[i]+2]….dp[i-1][j] 、仿照上面的形式,得到dp[i][j]=dp[i][j-1]+dp[i-1][j] - dp[i-1][j-1-x[i]];

綜上,遞推式為:

if(j >a[i] )

dp[i][j] = (dp[i-1][j] + dp[i][j-1] - dp[i-1][j-1-a[i]] +m)%m;

else

#include 

#include

#include

#include

#include

using

namespace

std;

const

int maxn =105;

int a[maxn];

int dp[maxn][maxn];

int main()

}printf("%d\n",dp[n][m]);

return

0;}

多重集組合數

問題描述 有n種物品,第i種物品有ai個。從這些物品中取m個,有多少種取法,求出方案數 模上m的餘數。sample input n 3 m 3 a m 10000 sample output 6 0 0 3,0 1 2,0 2 1,1 0 2,1 1 1,1 2 0 該題採用動態規劃。其中有乙個思想...

多重集組合數

題述 有n種物品,第i種物品有ai個。不同種類的物品可以互相區分但相同種類的無法區分。從這些物品中取出m個的話,有多少種取法?求出方案數模m的餘數。限制條件 1 n 1000 1 m 1000 1 ai 1000 2 m 10000 樣例 輸入3 5 1 2 3 10000輸出6 題記 dp i 1...

poj1173 多重集組合數

這道題的本質是將n個物品分成k堆,每堆物品個數大於0小於等於m的方案數。我們定義d i j 為前i堆物品總數為j的方案數,那麼d i j 的求解方法如下 其可化為d i j d i j 1 d i 1 j 1 d i 1 j 1 m 初始條件為d 0 0 1 d i 0 0 i 0 證明如下 對於第...