uva1639_Candy_概率_取对数技巧

 题意

两盒中各有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;
}

猜你喜欢

转载自blog.csdn.net/Anna__1997/article/details/81484127