您的位置:首页 > 其它

HDU 4465 Candy 概率 (2012成都区域赛B题)

2015-03-28 22:27 567 查看
题目大意:

就是现在有两个箱子里面都有n颗糖, 现在一个人每天选择一个箱子, 选择左边的箱子的概率是p, 选择右边箱子的概率是1 - p, 如果打开一个箱子的时候里面有糖就吃掉一颗, 否则会感到很失望然后去打开另外一个盒子, 现在一个人连续一段时间从选择的箱子里吃到糖, 在某一天是他打开箱子发现那个箱子是空的, 这天在他开另外一个箱子是时, 求另外一个箱子的剩余的糖的数量期望

大致思路:

思路写在代码注释里了

代码如下:

Result  :  Accepted     Memory  :  2160 KB     Time  :  514 ms

/*
* Author: Gatevin
* Created Time: 2015/3/28 13:15:47
* File Name: Chitoge_Kirisaki.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-10);
typedef long long lint;

/*
* 首先不难想到dp的做法, 用dp[i][j]表示两个箱子的糖剩余i和j的概率
* 那么dp

= 1, dp[i][j] = dp[i + 1][j]*p + dp[i][j + 1]*(1 - p)
* 最后sigma((dp[i][0]*(1 - p) + dp[0][i]*p)*i)即为答案
* 但是这个dp是O(n*n)的明显超时, 于是只好推公式了
*/

/*
* 如果最后是从左边盒子发现是空的, 那么右边在这是已经被吃了i个糖的概率
* 是C(n + i, i) * (1 - p)^i * p^n然后选择左边概率是p, 期望贡献是n - i
* 所以左边为空情况的期望是sigma(C(n + i, i) * (1 - p)^i * p^(n + 1)), 0 <= i <= n
* 对于右边箱子的期望是 sigma(C(n + i, i) * p^i * (1 - p)^(n + 1)), 0 <= i <= n
* 最终期望就是上面两式子之和, 由于精度原因不能直接计算例如 0.7^200000 导致nan
* 那么考虑计算的时候取对数进行计算用dp[i][0]表示第一个式子, dp[i][2]表示第二个式子
* 去对数来递推即可, 对于精度<Eps的就不要了, 防止nan的出现
*/
double dp[200010][2];

int main()
{
int n;
double p;
int cas = 1;
while(scanf("%d %lf", &n, &p) != EOF)
{
/* dp的做法, O(n*n)超时
memset(dp, 0, sizeof(dp));
dp

= 1;
for(int i = n; i >= 0; i--)
for(int j = n; j >= 0; j--)
{
if(i == n && j == n) continue;
if(i + 1 <= n)
dp[i][j] += dp[i + 1][j]*p;
if(j + 1 <= n)
dp[i][j] += dp[i][j + 1]*(1 - p);
}
double ans = 0;
for(int i = 1; i <= n; i++)
ans += i*dp[i][0]*(1 - p) + i*dp[0][i]*p;
printf("%.6f\n", ans);
*/
int st = 0;
double tmp1 = log2(n - st), tmp2 = log2(n - st);
for(int i = 1; i <= st; i++)
tmp1 += log2((n + i)*1./i), tmp2 += log2((n + i)*1./i);
tmp1 += log2(p)*(n + 1) + log2(1 - p)*st;
tmp2 += log2(1 - p)*(n + 1) + log2(p)*st;
dp[st][0] = tmp1, dp[st][1] = tmp2;
double ans = 0;
double Eps = log2(eps);//转化对数的Eps
if(dp[st][0] > Eps) ans += pow(2., dp[st][0]);
if(dp[st][1] > Eps) ans += pow(2., dp[st][1]);
for(int i = st + 1; i <= n; i++)
{
dp[i][0] = dp[i - 1][0] + log2(n - i) - log2(n - i + 1) + log2(n + i) - log2(i) + log2(1 - p);
dp[i][1] = dp[i - 1][1] + log2(n - i) - log2(n - i + 1) + log2(n + i) - log2(i) + log2(p);
if(dp[i][0] > Eps) ans += pow(2., dp[i][0]);
if(dp[i][1] > Eps) ans += pow(2., dp[i][1]);
}
printf("Case %d: %.6f\n", cas++, ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息