1. 程式人生 > >BZOJ 1426 收集郵票 概率DP

BZOJ 1426 收集郵票 概率DP

題目描述 Description
有n種不同的郵票,皮皮想收集所有種類的郵票。唯一的收集方法是到同學凡凡那裡購買,每次只能買一張,並且買到的郵票究竟是n種郵票中的哪一種是等概率的,概率均為1/n。但是由於凡凡也很喜歡郵票,所以皮皮購買第k張郵票需要支付k元錢。現在皮皮手中沒有郵票,皮皮想知道自己得到所有種類的郵票需要花費的錢數目的期望。

輸入描述 Input Description
一行,一個數字N

輸出描述 Output Description
要付出多少錢. 保留二位小數

樣例輸入 Sample Input
3

樣例輸出 Sample Output
21.25

資料範圍及提示 Data Size & Hint


1<=N<=10000

Solution

f[i]表示現在取到i張郵票,要取完剩下郵票的期望次數
顯然f[n]=0
現在已經取得i張郵票,所以下一次取郵票有in的概率取到已經有的,期望為inf[i]
nin的概率取到沒有的,期望為ninf[i+1],這次取郵票的期望為1,所以總期望為:

f[i]=inf[i]+ninf[i+1]+1
化簡可得:f[i]=f[i+1]+nni

g[i]表示現在取到i張郵票,要取完剩下郵票的期望價格
顯然g[n]=0
現在已經取得i張郵票,所以下一次取郵票有in的概率取到已經有的,期望為in(g[i]+f[i]+1),有nin的概率取到沒有的,期望為nin(g[i+1]+f[i+1]+1)所以總期望為:

g[i]=in(g[i]+f[i]+1)+nin(g[i+1]+f[i+1]+1)
化簡可得:g[i]=inif[i]+g[i+1]+f[i+1]+nni

前面的推導貌似很自然的樣子,但是為啥g[i]的推導式看著就那麼奇怪呢?
那是因為式子的結構表示的是每次都將後面取到的郵票費用+1(總費用+f[i]),再加上自己的費用(+1)
這樣就很好理解了

為啥不是f[0](f[0]+1)/2n我也想了很久
因為推導過來每次的貢獻是不相同的
比如說所有情況中有1次需要取2張,1次需要取3張,那麼總貢獻為(3+6)/2=4.5,而期望次數為2.5,顯然是不對的…

程式碼比思考簡單多了

#include <bits/stdc++.h>
using namespace std;
int n;
double f[10005],g[10005];
int main() {
    scanf("%d",&n);
    for(int i=n-1;~i;--i) {
        f[i]=f[i+1]+(1.0*n)/(1.0*(n-i));
        g[i]=(1.0*i)/(1.0*(n-i))*(f[i]+1)+g[i+1]+f[i+1]+1;
    }
    printf("%.2lf\n",g[0]);
    return 0;
}