參考
題目: 有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 證明如下 對於第...