UVa1639糖果(紫书333)(期望)

时间限制:1秒  内存限制:64M

【问题描述】

  有两个盒子各有n个糖果(n<=200000),每天随机选择一个:选第一个盒子的概率是p(0 ≤ p ≤ 1),第二个盒子的概率为1-p,然后吃掉其中的一颗。直到有一天,随机选择一个盒子打开一看,没糖了!现在请你计算另一个盒子里剩下的糖果数量的期望值。

【输入格式】

  包含多组数据。每组数据包含连个数:n和p,n是一个整数,表示每个盒子中的糖果数量,p是一个小数,表示每次打开第一个盒子的概率。

【输出格式】

  每组数据输出一个保留6位小数的实数,表示剩余糖果的期望值。

【输入样例】

10 0.400000
100 0.500000
124 0.432650
325 0.325100
532 0.487520
2276 0.720000

【输出样例】

Case 1: 3.528175
Case 2: 10.326044
Case 3: 28.861945
Case 4: 167.965476
Case 5: 32.601816
Case 6: 1390.500000

【数据范围】

1 ≤ n ≤ 2×10^5

【来源】

UVa1639糖果(紫书333)

现在开始发昨天的题,昨天刷太晚就直接走了,忘了发了。

这道题要发现一个公式,我们设第1个盒子吃完发现第二个盒子里还有i个的概率为f(i)(第二个盒子吃完的反过来就好了),那我们一共就吃了2*n-i个糖,而这些糖有n个是第一盒的n-i个第二盒的,所以为:C(n,2*n-i)P^(n+1)(1-P)^(n-i).

注意一共打开了第一个盒子n+1次,比较你最后要开一次发现没有了。

这道题理解不难,直接实现也很简单,但对于精度用对数处理的方法确实让我学到了很多(开始输出过0的我不想说什么)。

学习永无止境。

代码如下:

#include
#include
#include
#include
#include
using namespace std;
const int maxn=400005;

long double b[maxn];
int n;
double p,ans;

int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    b[0]=0;
    for(int i=1;i<=maxn-5;i++)
    b[i]=b[i-1]+log(i);
    int T=0;
    long double x,y,z,xxx,yyy;
    while(scanf("%d%lf",&n,&p)==2)
    {
        ans=0;
        xxx=log(p),yyy=log(1-p);
        for(int i=1;i<=n;i++)
        {
            x=b[2*n-i]-b[n]-b[n-i];
            y=x+(n+1)*xxx+(n-i)*yyy;
            z=x+(n+1)*yyy+(n-i)*xxx;
            ans+=(double)i*(exp(y)+exp(z));
        }
        printf("Case %d: %.6lf\n",++T,ans);
    }
    return 0;
}

你可能感兴趣的:(数学期望)