[WOJ3010] 骰子

题目描述:##

骰子是一个六面分别刻有一到六点的立方体,每次投掷骰子,理论上得到\(1\)\(6\)的概率都是\(1/6\)

有骰子一颗,连续投掷\(n\)次,问点数总和大于等于\(X\)的概率是多少?

题目分析:##

概率\(DP\)入门,由于是第一次做这类题,记录一下。

首先概率题的主要思路:
\(概率 = 合法方案数 / 总方案数\)

对于这道题,总方案数\(total=6^n\),所以重点在于怎么求合法方案数,即抛掷\(n\)次总和大于\(X\)的次数。
考虑\(dp\),设\(f[i][j]\)表示抽第\(i\)次总点数为\(j\)的方案数,容易得到状态转移方程\(f[i][j]=\sum\limits_{k=1}^6{f[i-1][j-k]}\)
$ ans = \frac{\sum\limits_{i=x}^{6*n}{f[n][i]}}{total} $

代码:##

#include<bits/stdc++.h>
#define N 30
#define M 300
using namespace std;
int read() {
	int cnt = 0; int f = 1;
	char c;
	c = getchar();
	while (!isdigit(c)) {
		if (c == '-') f = -1;
		c = getchar();
	}
	while (isdigit(c)) {
		cnt = cnt * 10 + c - '0';
		c = getchar();
	}
	return cnt * f;
}
long long gcd(long long x, long long y) {
	if (x == 0) return y;
	return gcd(y % x, x);
}
long long f[N][M], n, x, tot = 1, ans = 0;
int main() {
	n = read(); x = read();
	for (register int i = 1; i <= n; i++) tot *= 6;

	f[0][0] = 1;
	
	for (register int i = 1; i <= n; i++) 
		for (register int j = 1; j <= i * 6; j++) 
			for (register int k = 1; k <= 6; k++)
				if(j - k >= 0) 
					f[i][j] += f[i-1][j-k];
					
	for (register int i = x; i <= 6 * n; i++) 
		ans += f[n][i];
		
	if (ans == 0) {
		printf("0");
		return 0;
	}
	
	if (ans == tot) {
		printf("1");
		return 0;
	}
	
	long long GCD = gcd(ans, tot);
	ans /= GCD; tot /= GCD;
	printf("%lld/%lld", ans, tot);
	return 0;
}
posted @ 2019-04-20 09:59  kma_093  阅读(148)  评论(0编辑  收藏  举报