Candy UVA - 1639 (数学期望+大指数对数法)

本文探讨了两个装有相同数量糖果的盒子中,按特定概率每天取出一颗糖果,直至其中一个盒子空置时,另一盒子剩余糖果数的数学期望问题。通过引入二项式定理和对数技巧,有效解决了大规模数据下的计算问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

VJ原题

题意:

两个盒子,每个里面都有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);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值