1. 程式人生 > >Uva1639(概率期望/對數處理避免丟失精度)

Uva1639(概率期望/對數處理避免丟失精度)

div for class can ble uva name 方法 color

Uva1639

題意:

有兩個盒子各有n個糖果(n<=200000),每天隨機選擇一個:選第一個盒子的概率是p(0 ≤ p ≤ 1),第二個盒子的概率為1-p,然後吃掉其中的一顆。直到有一天,隨機選擇一個盒子打開一看,沒糖了!現在請你計算另一個盒子裏剩下的糖果數量的期望值。

解法:

我們假設到第n天的時候取得是第1個盒子的糖,此時第2個盒子有i顆糖,則在此之前打開了n+(n-i)次盒子, 其中n次打開了第一個盒子,(n-i)次打開了第二個盒子,則概率是C(2n-i,n)*p^(n+1)*(1-p)^n-i。

由於n高達20w,所以二次項系數會非常大,而後面的概率會非常小,所以如果直接計算會爆精度,所以這裏我們用求對數的方法進行計算

 1 #include<iostream>
 2 #include<cmath>
 3 using namespace std;
 4 typedef long double lb;
 5 const int maxn = 2e5 + 5;
 6 long double logF[2 * maxn + 66];
 7 
 8 void generate() {
 9     //預處理出n!的log值
10     logF[0] = 0;
11     for (int i = 1; i <= maxn; i++)
12         logF[i] = logF[i - 1
] + log(i); 13 } 14 // C(n,m) = n!/(m!(n-m)!) 15 long double logC(int n, int m) { 16 return logF[n] - logF[m] - logF[n - m]; 17 } 18 19 int main() { 20 int n; double p; 21 generate(); 22 int kase = 1; 23 while (scanf("%d%lf", &n, &p)!=EOF) { 24 double ans = 0; 25 for
(int i = 0; i <= n; i++) { 26 long double v1 = logC(2 * n - i, n) + (n + 1)*log(p) + (n - i)*log(1 - p); 27 long double v2 = logC(2 * n - i, n) + (n + 1)*log(1 - p) + (n - i)*log(p); 28 ans += (i*(exp(v1) + exp(v2))); 29 } 30 printf("Case %d: %.6lf\n", kase++, ans); 31 } 32 return 0; 33 }

Uva1639(概率期望/對數處理避免丟失精度)