UVA

X表示剩下的糖数量,如果最后打开的是p对应的盒子。划分:Xi表示剩下i个糖,最后一次选的概率为p,

前面的服从二项分布。根据全概率公式和期望的线性性,求和就好了。

精度处理要小心,n很大,组合数会很大,p的部分很小,要取对数,而且中间计算精度也要用long double才够。

组合数的对数预处理一下或者递推一下就好了。

/*********************************************************
*      --------------Tyrannosaurus---------              *
*   author AbyssalFish                                   *
**********************************************************/
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef long double ld;

const int maxn2 = 4e5+1;
ld sum_fac_ln[maxn2];

//inline double ln_(int x) { return sum_fac_ln[x]-sum_fac_ln[x-1]; }
inline ld ln_C(int m,int n)
{
    return sum_fac_ln[m]-sum_fac_ln[n]-sum_fac_ln[m-n];
}

const ld eps = 1e-11;


double solve(int n, ld p)
{
    ld q = 1-p;
    if(p < eps || q < eps) return n;
    ld E = 0;
    int _2n = n<<1;
    ld ln_p = log(p), ln_q = log(q);
    ld nln_p = (n+1)*ln_p;
    ld nln_q = (n+1)*ln_q;
    for(int x = 1; x <= n; x++){
        ld lnC = ln_C(_2n-x,n);
        E += x*( exp( lnC + nln_p + (n-x)*ln_q ) + exp(lnC + nln_q + (n-x)*ln_p ) );
    }
    return E;
}

//#define LOCAL
int main()
{
#ifdef LOCAL
    freopen("in.txt","r",stdin);
#endif
    for(int i = 2; i < maxn2; i++) sum_fac_ln[i] = log((ld)i);
    for(int i = 2; i < maxn2; i++) sum_fac_ln[i] += sum_fac_ln[i-1];
    int kas = 0, n;
    double p;

    while(~scanf("%d%lf",&n,&p)){
        printf("Case %d: %.6lf
", ++kas, solve(n,p));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/jerryRey/p/4963351.html