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\n", 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\n", ans1);
return 0;
}
转载需注明出处。