题意
两盒中各有n的糖果,每次以概率 p 取其中一只盒子的糖果,概率 1 - p 取另一只当打开一只盒子发现为空时另一只盒子中的糖果数的期望。
思路
考虑先发现0号盒子为空时的期望,取得过程为一个序列 x1 x2 x3 ... xt x(t + 1)
x(t + 1) = 0, x1...xt 为 01 得排列其中有 n 个0,i 个1(注意要考虑最后一次以p得概率打开0号盒子实际为空)
期望:E = ∑ C(n + i, i) * p^(n + 1) * (1 - p)^i * (n - i)
概率部分有阶乘可用递推 简化计算。
题目 n 范围很大,p 的幂次损失精度至0,阶乘部分数又很大(即一系列乘数从小到大相乘结果为0)
可把乘法转为对数的加法
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define INF 0x3f3f3f3f
#define rep0(i, n) for (int i = 0; i < n; i++)
#define rep1(i, n) for (int i = 1; i <= n; i++)
#define rep_0(i, n) for (int i = n - 1; i >= 0; i--)
#define rep_1(i, n) for (int i = n; i > 0; i--)
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define mem(x, y) memset(x, y, sizeof(x))
#define MAXN 200010
using namespace std;
int n;
long double solve(long double p)
{
long double lnq = (n + 1) * log(p), ans = exp(lnq) * n;
for (int i = 1; i < n; i++)
{
lnq += log(n + i) - log(i) + log(1 - p);
ans += exp(lnq) * (n - i);
}
return ans;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif // ONLINE_JUDGE
int kase = 0;
double p;
while (scanf("%d %lf", &n, &p) != EOF)
{
double ans = solve(p) + solve(1 - p);
printf("Case %d: %.6f\n", ++kase, ans);
}
return 0;
}