HDU-4248 A Famous Stone Collector 组合数学 DP
HDU 4248
题意:
给定n种颜色不同的石子,每种石头有 num[i] 个。从中取石子,问能够得到多少种不同的序列。
\[n \leq 100,num[i]\leq 100
\]
数据范围比较小,考虑dp
\[dp[i][j]表示选前i种石头,且选的石头总数为j时的不同序列个数
\]
有转移方程
\[dp[i][j] = \sum dp[i - 1][j - k] \cdot \tbinom{j}{k} \quad k\leq num[i]
\]
即考虑第i种石头的贡献,也就是第j个中选k个位置给第i种石头。
\[ans = \sum dp[n][i]\quad i \leq 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("");
}
}