您的位置:首页 > 其它

HDU 4465 Candy 概率期望值的对数优化

2017-10-04 15:50 585 查看
题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=4465

Candy

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 2888    Accepted Submission(s): 1304
Special Judge


[align=left]Problem Description[/align]
LazyChild is a lazy child who likes candy very much. Despite being very young, he has two large candy boxes, each contains n candies initially. Everyday he chooses one box and open it. He chooses the first box with probability p and
the second box with probability (1 - p). For the chosen box, if there are still candies in it, he eats one of them; otherwise, he will be sad and then open the other box.

He has been eating one candy a day for several days. But one day, when opening a box, he finds no candy left. Before opening the other box, he wants to know the expected number of candies left in the other box. Can you help him?
 

[align=left]Input[/align]
There are several test cases.

For each test case, there is a single line containing an integer n (1 ≤ n ≤ 2 × 105) and a real number p (0 ≤ p ≤ 1, with 6 digits after the decimal).

Input is terminated by EOF.
 

[align=left]Output[/align]
For each test case, output one line “Case X: Y” where X is the test case number (starting from 1) and Y is a real number indicating the desired answer.

Any answer with an absolute error less than or equal to 10-4 would be accepted.
 

[align=left]Sample Input[/align]

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

 

[align=left]Sample Output[/align]

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

 

[align=left]Source[/align]
2012 Asia Chengdu Regional Contest 
【分析】:

原来这是紫书上的一道题。。

题意有两个盒子,各n个糖果,每天从其中的1个盒子中拿一个糖果。

每天从一个盒子拿的概率是p,另一个(1-p);

当某一天打开一个盒子发现空时,另一个盒子中的糖果数量的期望值是多少?

至关重要的一点,起初忽略了,上面红字!这一天相当于拿糖时空手而归。

假设A盒子,B盒子。取A的概率为p。

假设发现A空了的那一天,从B中已经取走了i个

则这种事件发生的概率为 C(n+i, i) * p^(n+1)
*(1-p)^i

但是n的取值范围可达20万,组合数特别大,p的n+1次方又特别小,直接算会损失精度。

自然对数的优化登场。

令V = C(n+i, i) * p^(n+1) *(1-p)^i  

这三个数相乘,整体取对数,得ln(V)= ln(C(n+i, i))
+ (n+1)*ln(p)  +  i*ln(1-p)  

计算过程用对数,算完之后得到ln(V)

那么该状态的概率V = e^ln(V),这时的概率将大大减少精度损失。

然后的话就是遍历i求每个状态的V*i ,求和,即为答案。别忘了A和B盒子交换一下的情况。

另外,组合数也是对数优化的,把求组合数过程的阶乘,取对数ln(n!) =ln(n) + ln(n-1) +.....

这样就能不爆longlong

【代码】:#include <stdio.h>
#include <math.h>
#include <string.h>
#include <iostream>
using namespace std;
double lnc[404040];
double lns[401010];//ln(i)的前n项和
void init()
{
lns[1]=0;//特殊
for(int i=1;i<=200010;i++)
lns[i]=log(i)+lns[i-1];
}
double lnC(int n,int m)
{
if(m==0)return 0;
return (lns
-lns[n-m])-lns[m];
}
int main()
{
init();
int n,r=1;
double p;
while(cin>>n>>p)
{
double ans=0;
for(int i=0;i<n;i++)
{
double t=lnC(n+i,i)+(n+1)*log(p)+i*log(1-p);
ans+=exp(t)*(n-i);
t=lnC(n+i,i)+(n+1)*log(1-p)+i*log(p);//换盒子
ans+=exp(t)*(n-i);
}
printf("Case %d: %lf\n",r++,ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: