考场被题目秀到了。概率、期望。。。。。。
(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;
}