Hdu 4465 Candy (快速排列组合+概率)
题目链接:
题目描述:
有两个箱子,每个箱子有n颗糖果,抽中第一个箱子的概率为p,抽中另一个箱子的概率为1-p。每次选择一个箱子,有糖果就拿走一颗,没有就换另外一个箱子。问换箱子的时候,另外一个箱子中剩下糖果的期望值。
解题思路:
注意题目描述,其中任意一个箱子没有糖果,另一个箱子中剩下糖果个数的期望,而不是第一个箱子没有糖果。不是把其中一个箱子取空时,另一个箱子剩下糖果的期望,而是其中一个箱子取空再换另外一个箱子时,这个箱子的期望。
可以根据期望性质画出公式:ans = (n-i) * C(n+i,n) * (p^(n+1)*(1-p)^i + (1-p)^(n+1)*p^i) (0<=i<=n);新的问题又来了,C(n+i,n)由于n的原因可能会向上溢出,而p^(n+1)又可能会很小,然后向下溢出。可以分别对他们进行取log,log(C(n+i,n))范围变小,log(p^(n+1))变成负数,方便保存。
1 /* 2 ******未处理精度的代码,推论严密美丽也无卵用******** 3 期望公式Ε=∑ P * N p为概率 n为数量 4 P=p*C(n,m)*p^n*(1-p)^(m-n) 5 c(m,n)=c(m-1,n)*m/(m-n) 6 概率 7 m=0 p^(n+1) 8 m=1 p^(n+1)q 9 m=2 p^(n+1)q^2 10 */ 11 #include <cstdio> 12 #include <iostream> 13 #include <algorithm> 14 using namespace std; 15 16 int main () 17 { 18 int t, i, l = 1; 19 double ans, p1, p2, res1, res2; 20 while (scanf ("%d %lf", &t, &p1) != EOF) 21 { 22 p2 = (1.0 - p1); 23 res1 = t * p1; 24 ans = 1; 25 res2 = t * p2; 26 for (int i=1; i<=t; i++) 27 { 28 ans *= p1 * p2 * (t + i) / i; 29 res1 += ans * (t - i); 30 res1 *= p1; 31 res2 += ans * (t - i); 32 res2 *= p2; 33 } 34 printf ("Case %d: %6lf\n", l++, res1+res2); 35 } 36 return 0; 37 }
1 /* 2 取log处理精度问题,exp还原结果 3 */ 4 #include <cmath> 5 #include <cstdio> 6 #include <iostream> 7 #include <algorithm> 8 using namespace std; 9 const int maxn = 400005; 10 double Logf[maxn]; 11 void init () 12 { 13 Logf[0] = 0; 14 for (int i=1; i<maxn; i++) 15 Logf[i] = Logf[i-1] + log(i*1.0); 16 } 17 double C (int m, int n) 18 { 19 return Logf[m] - Logf[n] - Logf[m-n]; 20 } 21 int main () 22 { 23 int n, cas = 1; 24 double p1, p2, ans; 25 init (); 26 while (scanf ("%d %lf", &n, &p1) != EOF) 27 { 28 ans = 0; 29 p2 = 1.0 - p1; 30 p1 = log(p1); 31 p2 = log(p2); 32 for (int i=0; i<n; i++) 33 { 34 ans += ((n-i) * exp(C(n+i, n) + (n+1)*p1 + i*p2)); 35 ans += ((n-i) * exp(C(n+i, n) + (n+1)*p2 + i*p1)); 36 } 37 printf ("Case %d: %f\n", cas++, ans); 38 } 39 return 0; 40 }
本文为博主原创文章,未经博主允许不得转载。