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 200000 long 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; }
原文地址:http://blog.csdn.net/u014800748/article/details/43953809