「演算法筆記」期望 DP 入門
一、數學期望
1. 由來
在 \(17\) 世紀,有一個賭徒向法國著名數學家帕斯卡挑戰,給他出了一道題目:甲乙兩個人賭博,他們兩人獲勝的機率相等,比賽規則是先勝三局者為贏家,一共進行五局,贏家可以獲得 \(100\) 法郎的獎勵。當比賽進行到第四局的時候,甲勝了兩局,乙勝了一局,這時由於某些原因中止了比賽,那麼如何分配這 \(100\) 法郎才比較公平?
甲輸掉後兩局的可能性只有 \(\frac{1}{2} \times \frac{1}{2}=\frac{1}{4}\),也就是說甲贏得後兩局或後兩局中任意贏一局的概率為 \(1-\frac{1}{4}=\frac{3}{4}\),甲有 \(75\%\)
可見,雖然不能再進行比賽,但依據上述可能性推斷,甲乙雙方最終勝利的客觀期望分別為 \(75\%\) 和 \(25\%\),因此甲應分得獎金的 \(100\times 75\%=75\) (法郎),乙應分得獎金的的 \(100×25\%=25\) (法郎)。這個故事裡出現了“期望”這個詞,數學期望由此而來。(¿)
(摘自百度百科)
2. 定義
數學期望是實驗中每次可能結果的概率乘以其結果的綜合,它的定義式為:
\[E(X)=\sum\limits_{k=1}^\infty x_i p_i \]其中 \(i\) 是所有可能發生的事件,\(x_i\) 為事件的權值,\(p_i\) 為事件發生的概率。
3. 性質
設 \(C\) 為一個常數, \(X\) 和 \(Y\) 是兩個隨機變數。以下是數學期望的重要性質:
1.\(E(C)=C\)
2.\(E(CX)=CE(X)\)
3.\(E(X+Y)=E(X)+E(Y)\)
4. 當 \(X\) 和 \(Y\) 相互獨立時,\(E(XY)=E(X)E(Y)\)
二、例題
1.SP1026 FAVDICE - Favorite Dice
題目大意:一個 \(n\) 面的骰子,求期望擲幾次能使得每一面都被擲到。\(n\leq 6000\)。
Solution:
結論:\(1+\frac{n}{n-1}+\frac{n}{n-2}+...+n=\sum\limits_{i=1}^n \frac{n}{i}\)
令 \(f[i]\) 表示已經擲出 \(i\) 個不同的面,還期望擲多少次能使得每一面都被擲到。
顯然 \(f[n]=0\)。
對於所有 \(f[i]\ (i\neq n)\),有兩種情況:
- 有 \(\frac{i}{n}\) 的概率擲到重複的面,則還需擲 \(f[i]\) 次。
- 有 \(\frac{n-i}{n}\) 的概率擲到新的面,則還需擲 \(f[i+1]\) 次。
\(f[i]=(\frac{i}{n} f[i]+\frac{n-i}{n} f[i+1])+1\)
整理得,\(f[i]=f[i+1]+\frac{n}{n-i}\)
因此 \(ans=f[0]=\sum\limits_{i=n-1}^{0} \frac{n}{n-i}=\sum\limits_{i=1}^n \frac{n}{i}\)
#include<bits/stdc++.h> #define int long long using namespace std; int t,n; double ans; signed main(){ scanf("%lld",&t); while(t--){ scanf("%lld",&n),ans=0; for(int i=1;i<=n;i++) ans+=1.0*n/i; printf("%.2lf\n",ans); } return 0; }
2. BZOJ 1419 Red is good
題目大意:桌面上有 \(R\) 張紅牌和 \(B\) 張黑牌,隨機打亂順序後放在桌面上,開始一張一張地翻牌,翻到紅牌得到 \(1\) 美元,黑牌則付出 \(1\) 美元。可以隨時停止翻牌,在最優策略下平均能得到多少錢。\(0\leq R,B \leq 5000\)。
Solution:
令 \(f[r][b]\) 表示剩下 \(r\) 張紅牌、\(b\) 張黑牌的期望收益。
首先考慮邊界情況。
當 \(r=0\),即目前已經沒有紅牌時,停止翻牌,則 \(f[r][b]=0\)。當 \(b=0\),即剩下的牌沒有黑牌時,肯定會把剩下的紅牌全部翻掉,則 \(f[r][b]=r\)。
討論其他情況。
有 \(\frac{r}{r+b}\) 的概率翻到一張紅牌,並帶來 \(1\) 的收益;有 \(\frac{b}{r+b}\) 的概率翻到一張黑牌,並帶來 \(1\) 的損失。
那麼顯然\(f[r][b]=max(0,\frac{r}{r+b}(1+f[r-1][b])+\frac{b}{r+b}(-1+f[r][b-1])\)。因為我們採用的是最優策略,所以當此時的局面已經不足以帶來大於\(0\)的期望收益時,應該停止翻牌,所以最後還要和\(0\)取\(max\)。
由於卡空間,需要使用滾動陣列。
#include<bits/stdc++.h> #define int long long using namespace std; const int N=5010; int n,m; double f[2][N],ans; signed main(){ scanf("%lld%lld",&n,&m); for(int r=1;r<=n;r++){ f[r%2][0]=1.0*r; for(int b=1;b<=m;b++) f[r%2][b]=max(0.0,1.0*r/(r+b)*(1+f[(r-1)%2][b])+1.0*b/(r+b)*(-1+f[r%2][b-1])); } printf("%.6lf\n",1.0*floor(f[n%2][m]*1e6)/1e6); return 0; }
3. BZOJ 4318 OSU!
題目大意:給出一串數,每個數字有 \(a[i]\) 的概率是 \(O\),這串數字的分數定義為每一段極長連續的 \(O\) 的長度的立方和,\(OXXOO\) 的分數就是 \(1^3+2^3=9\),求期望分數。\(N\leq 10^5\)。
Solution:
令 \(y[i]\) 表示到 \(i\) 為止連續打出多少個 \(O\)。
有 \(p=a[i]\) 的概率打出 \(O\),則有 \(p\) 的概率 \(y[i]=y[i-1]+1\);有 \(1-p\) 的概率打出的不是 \(O\),則有 \(1-p\) 的概率 \(y[i]=0\)。
\(E(y[i])=E(p\times (y[i-1]+1))=p\times (E(y[i-1])+1)\)
因為 \((x+1)^3=x^3+3x^2+3x+1\),所以還需要維護平方和。每打出 \(1\) 個 \(O\),答案 \((x+1)^3\) 比原答案 \(x^3\) 相比多了 \(3x^2+3x+1\)。
\(E(y[i]^2)=E(p\times (y[i-1]+1)^2)=p\times (E(y[i-1]^2)+2\times E(y[i-1])+1)\)
可以分別用 \(f_1[i],f_2[i]\) 維護 \(E(y[i]),E(y[i]^2)\)。
\(f_1[i]=p\times (f_1[i-1]+1)\)
\(f_2[i]=p\times(f_2[i-1]+2\times f_1[i-1]+1)\)
那麼 \(ans[i]=ans[i-1]+p\times (3\times f_2[i-1]+3\times f_1[i-1]+1)\),最終的答案為 \(ans[n]\)。
#include<bits/stdc++.h> #define int long long using namespace std; const int N=1e5+5; int n; double a[N],f1[N],f2[N],ans[N]; signed main(){ scanf("%lld",&n); for(int i=1;i<=n;i++) scanf("%lf",&a[i]); for(int i=1;i<=n;i++){ f1[i]=a[i]*(f1[i-1]+1); f2[i]=a[i]*(f2[i-1]+2*f1[i-1]+1); ans[i]=ans[i-1]+a[i]*(3*f2[i-1]+3*f1[i-1]+1); } printf("%.1lf\n",ans[n]); return 0; }
4. HDU 4035 Maze
題目大意:有一個樹形的迷宮,有 \(N\) 個房間以及 \(N-1\) 條通道將它們連通,一開始在 \(1\) 號房間,每進入一個房間 \(i\),有 \(kill[i]\) 的概率被陷阱殺死回到房間 \(1\),有 \(s[i]\) 的概率找到出口逃離迷宮,如果沒有找到出口也沒有被殺,那麼就在與該房間相連的通道中等概率隨機選一條走,求逃離迷宮所需要走的通道數的期望值。(如果不能逃離輸出impossible
)。\(T\leq 30,N\le 10^4\)。