例题10-17 糖果 UVa1639

来源:互联网 发布:nba2013 14总决赛数据 编辑:程序博客网 时间:2024/05/02 04:16

1.题目描述:点击打开链接

2.解题思路:根据题意,不妨设最后打开第一个盒子,此时第二个盒子还有i颗糖果,因此这之前一共打开了n+(n-i)次盒子,其中n次取盒子1,n-i次取盒子2,取法一共有C(2*n-i,n)种,因此盒子2还剩i颗糖果时的概率是C(2*n-i,n)*p^(n+1)*(1-p)^(n-i)。注意最后一次打开盒子1的概率也要算上。有了概率,根据期望的定义不难求出答案。但需要注意的是,由于n可能非常大,因此要利用对数来计算,防止过多的精度损失。为了提高程序效率,可以事先算好n!取自然对数的值,便于后续计算;另外,p的边界可能是0或1,因此要单独处理。

3.代码:

#define _CRT_SECURE_NO_WARNINGS #include<iostream>#include<algorithm>#include<string>#include<sstream>#include<set>#include<vector>#include<stack>#include<map>#include<queue>#include<deque>#include<cstdlib>#include<cstdio>#include<cstring>#include<cmath>#include<ctime>#include<functional>using namespace std;#define N 200000long double v1, v2;long double Log[2*N+100];void init()//预处理,计算n!的自然对数值{for (int i = 1; i <= N * 2; i++)Log[i] = Log[i - 1] + log(i);}int main(){//freopen("test.txt", "r", stdin);int rnd = 0;int n;double p;init();while (cin >> n >> p){double ans = 0.0;printf("Case %d: ", ++rnd);if (p == 0 || p == 1)ans = n;//特殊处理else{long double p1 = log(p);long double q1 = log(1 - p);for (int i = 1; i <= n; i++){long double c = Log[2 * n - i] - Log[n] - Log[n - i];v1 = c + (n + 1)*p1 + (n - i)*q1;v2 = c + (n + 1)*q1 + (n - i)*p1;ans += (double)i*(exp(v1) + exp(v2));}}printf("%.6lf\n", ans);}return 0;}

0 0
原创粉丝点击