题意:
两个盒子,每个里面都有n颗糖果,每天拿在其中一个盒子里拿一颗糖果,概率为p和1-p,直到有一个盒子的糖全被吃完了,求另一个盒子剩余的糖的数学期望。
思路:
利用二项式定理和基本的概率知识很容易得到结论:
第i次打开盒子1没糖的概率C(2n-1,n)p^(n+1)(1-p)^(n-i)
第i次打开盒子2没糖的概率C(2n-1,n)(1-p)^(n+1)p^(n-i)。
由于n最大有二十万,所以直接算组合数,结果将会巨大,直接爆掉。所以这里运用到了一个技巧就是对等式两边进行取对数。
得到
v1(i) = ln(C(2n-i, n)) + (n+1)ln(p) +(n-i)ln(1-p),
v2(i) = ln(C(2n-i, n)) + (n+1)ln(1-p) +(n-i)ln(p)
最终答案为 Σ{ i*(e^v1(i) +e^v2(i) ) }
这个题新学到了如何获得取对数之后的组合数。代码如下
long double logfac[maxn * 2 + 1];
for (int i = 1; i <= maxn * 2; i++)
logfac[i] = logfac[i - 1] + log(i);
long double logc(int n, int m)
{
return logfac[n] - logfac[m] - logfac[n - m];
}
然后根据公式算出答案即可
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
#include <stack>
#include <string>
#include <list>
#include <cstdlib>
#include <memory>
#include <cstring>
#include <sstream>
#include <list>
#include <deque>
#include <bitset>
#include <vector>
using namespace std;
#define INF 1e18
#define PI 3.141592653579
#define FRER() freopen("input.txt" , "r" , stdin);
#define FREW() freopen("output.txt" , "w" , stdout);
#define QIO std::ios::sync_with_stdio(false)
#define mem(a, b) memset(a , b , sizeof(a))
const double eps = 1e-8;
typedef long long ll;
const int maxn = 200000 + 5;
long double logfac[maxn * 2 + 1];
long double logc(int n, int m)
{
return logfac[n] - logfac[m] - logfac[n - m];
}
int main()
{
// FRER();
// FREW();
int n;
double p;
int cas = 1;
for (int i = 1; i <= maxn * 2; i++)
logfac[i] = logfac[i - 1] + log(i);
while (scanf("%d%lf", &n, &p) != EOF)
{
long double v1 = 0, v2 = 0;
double res = 0.0;
for (int i = 1; i <= n; i++)
{
v1 = logc(n * 2 - i, n) + (n + 1) * log(p) + (n - i) * log(1-p);
v2 = logc(n * 2 - i, n) + (n + 1) * log(1 - p) + (n - i) * log(p);
res += (double) i * (exp(v1) + exp(v2));
}
printf("Case %d: %.6lf\n", cas++, res);
}
}