jzoj 100004. 【NOI2017模拟.4.1】 Dice

考场被题目秀到了。概率、期望。。。。。。

(awsl)

我们设:
(g[i][j])表示投(i)次,最后为(j)的概率。
(f[i][j])表示投(i)次,最后为(j)的期望。
(s[i][j])表示投(i)次,最后为(j)的所有数和的平方的期望。

前面的转移方程显然:
(g[i][j] = g[i-1][k]*p[j]/(1-p[k])) (k=1...6&&k!=j)
(f[i][j] = f[i-1][k]*p[j]/(1-p[k]) + g[i][j] * j) (k=1...6&&k!=j)

而对于(s)的转移,我们可以回到定义。
我们设之前的数的和为(k)
(s[i][j])的期望为((k+j)^2)的期望。
(k^2+2*j*k+j^2)
(k^2)可以由之前(s)转移。
(2*j*k)可以由(f)来转移。
(j^2)则是(g)来转移。
总的来说,就是:
(s[i][j] = s[i-1][k]*p[j]/(1-p[k]) + 2 * (f[i][j]-g[i][j] * j) * j + g[i][j] * j * j)(k=1...6&&k!=j)
然后转移即可。(PS:有精度问题)
精度问题可以看题解,题解的特有解决方法很妙。

code

#include <cstdio>
#define N 100010
#define db long double
#define mem(x, a) memset(x, a, sizeof x)
#define mpy(x, y) memcpy(x, y, sizeof y)
#define fo(x, a, b) for (int x = (a); x <= (b); x++)
#define fd(x, a, b) for (int x = (a); x >= (b); x--)
using namespace std;
int n, tot = 0;
db p[7], f[N][7], g[N][7], s[N][7], v[7];
db ans = 0, ans1 = 0;

int main()
{
	freopen("dice.in", "r", stdin);
	freopen("dice.out", "w", stdout);
	fo(i, 1, 6) scanf("%Lf", &p[i]);
	scanf("%d", &n);
	fo(i, 1, 6) g[1][i] = p[i], ans += g[1][i] * i;
	fo(i, 2, n)
		fo(j, 1, 6)
		{
			fo(k, 1, 6)
			{
				if (j == k) continue;
				g[i][j] += g[i - 1][k] * p[j] / (1 - p[k]);
			}
			ans += g[i][j] * j;
		}
	printf("%.15Lf
", ans);
	fo(i, 1, 6) v[i] = i - ans / n;
	fo(i, 1, 6) s[1][i] = p[i] * v[i] * v[i], f[1][i] = p[i] * v[i];
	fo(i, 2, n)
		fo(j, 1, 6)
		{
			fo(k, 1, 6)
			{
				if (j == k) continue;
				f[i][j] += f[i - 1][k] * p[j] / (1 - p[k]);
				s[i][j] += s[i - 1][k] * p[j] / (1 - p[k]);
			}
			s[i][j] += 2 * f[i][j] * v[j] + g[i][j] * v[j] * v[j];
			f[i][j] += g[i][j] * v[j];
		}
	fo(i, 1, 6) ans1 += s[n][i];
	printf("%.15Lf
", ans1);
	return 0;
}
转载需注明出处。
原文地址:https://www.cnblogs.com/jz929/p/12187866.html