1. 程式人生 > 實用技巧 >HDU - 4248 A Famous Stone Collector 組合數學 DP

HDU - 4248 A Famous Stone Collector 組合數學 DP

給定n種顏色不同的石子,每種石子有num[i]個。從中取石子,問能得到多少種不同的序列。

n <= 100, num <= 100。

資料範圍比較小,考慮dp

dp[i][j] 表示選前i種石頭,且石頭總數為j時的不同的序列的個數。

轉移方程 dp[i][j] = sum(dp[i - 1][j - k ] * C(j, k)) k <= num[i]。

考慮第i種石頭的貢獻,也就是j個種選k個位置給第i種石頭。

ans = sigma dp[n][i] i <= sum

ll C[10015][105];

void init() {
    for (int i = 0; i < 10015
; i++) { C[i][0] = 1; for (int j = 1; j <= i && j <= 105; j++) C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD; } } int num[105]; ll dp[105][10005]; int main() { int n; init(); int kase = 1; while (~scanf("%d", &n)) { ll sum = 0;
for (int i = 1; i <= n; i++) num[i] = readint(); memset(dp, 0, sizeof dp); dp[0][0] = 1; for (int i = 1; i <= n; i++) { sum += num[i]; for (int j = 0; j <= sum; j++) { for (int k = 0; k <= num[i] && j >= k; k++) dp[i][j]
+= dp[i - 1][j - k] * C[j][k], dp[i][j] %= MOD; } } ll res = 0; for (int i = 1; i <= sum; i++) res += dp[n][i], res %= MOD; printf("Case %d: ", kase++); Put(res); puts(""); } }