题目
统计n个骰子(六面体形状),投掷出总和为k时的概率。
分析
动态规划(dp)。打表计算查询输出。
状态定义:f(n,k)为n个骰子,投掷德 值的和为k的概率;
转移方程:f(n,k)= [ f(n-1,k-1)+ f(n-1,k-2)+ f(n-1,k-3)+ f(n-1,k-4)+ f(n-1,k-5)+ f(n-1,k-6)] / 6
说明
使用unsigned long long一直WA,换成long long就过了。
#include <stdio.h>
#include <stdlib.h>
typedef long long ll;
ll dp_a[30][151] = {0};
ll dp_b[30][151] = {0};
ll gcd(ll a, ll b)
{
return a%b?gcd(b, a%b):b;
}
int main()
{
// make list using dp
for (int i = 1; i <= 6; ++ i) {
dp_a[1][i] = 1;
dp_b[1][i] = 6;
}
for (int i = 2; i <= 24; ++ i) {
for (int j = 6*i; j >= i; -- j) {
dp_a[i][j] = 0ULL;
for (int k = 1; k <= 6; ++ k) {
dp_a[i][j] += dp_a[i-1][j-k];
}
dp_b[i][j] = dp_b[i-1][i-1]*6;
}
}
int n, k;
while (~scanf("%d%d", &n, &k) && n+k) {
if (k > 6*n) {
printf("0\n");
}else if (k == 0) {
printf("1\n");
}else {
ll denominator = dp_b[n][n];
ll numerator = 0ULL;
for (int i = k; i <= 6*n; ++ i) {
numerator += dp_a[n][i];
}
if (denominator == numerator) {
printf("1\n");
}else if (numerator == 0ULL) {
printf("0\n");
}else {
ll remainder = gcd(denominator, numerator);
printf("%lld/%lld\n", numerator/remainder, denominator/remainder);
}
}
}
return 0;
}