題目連結:http://acm.sgu.ru/problem.php?contest=0&problem=495
題意:
有n個禮物盒,m個人。
最開始每個禮物盒中都有一個禮物。
m個人依次隨機選一個盒子,如果有禮物就拿走,然後放回空盒子。
問你所有人得到總禮物數的期望。
題解:
三種做法:期望dp,概率dp,推公式
一、期望dp
表示狀態:
dp[i] = 該第i個人拿箱子時的總禮物的期望
找出答案:
ans = dp[m]
如何轉移:
對於第i個人,拿到禮物或沒拿到。
(1)φ(沒拿到) = dp[i] P(沒拿到) = dp[i]/n
(2)φ(拿到) = dp[i]+1 P(拿到) = (n-dp[i])/n
綜上:dp[i+1] = dp[i] * dp[i]/n + (dp[i]+1) * (n-dp[i])/n
邊界條件:
dp[0] = 0
還沒開始拿的時候禮物數為0
二、概率dp
表示狀態:
dp[i] = 第i個人拿到禮物的概率
找出答案:
ans = ∑ dp[i]
每個人得到禮物的概率 * 得到禮物的數量(為1) 之和。
如何轉移:
對於第i個人,拿到禮物或沒拿到。
(1)沒拿到:dp[i+1]依然等於dp[i],沒拿到禮物的概率為1-dp[i].
(2)拿到:dp[i+1] = dp[i] - 1/n,拿到的概率為dp[i].
綜上:dp[i+1] = dp[i] * (1 - dp[i]) + (dp[i] - 1/n) * dp[i]
邊界條件:
dp[0] = 1
所有盒子裡都有禮物,第0個人一定拿到禮物。
三、推公式
m個人是獨立的。
對於每個禮物不被人選中的概率為((n-1)/n)^m
那麼不被選中的禮物數的期望就是 n*((n-1)/n)^m
所以答案就是 n-n*((n-1)/n)^m
AC Code(expectation):
1 // state expression:
2 // dp[i] = expectation
3 // i: considering ith person
4 //
5 // find the answer:
6 // ans = dp[m]
7 //
8 // transferring:
9 // dp[i+1] = dp[i] * dp[i]/n + (dp[i]+1) * (n-dp[i])/n
10 //
11 // boundary:
12 // dp[0] = 0
13 #include <iostream>
14 #include <stdio.h>
15 #include <string.h>
16 #define MAX_M 100005
17
18 using namespace std;
19
20 int n,m;
21 double dp[MAX_M];
22
23 int main()
24 {
25 scanf("%d%d",&n,&m);
26 for(int i=0;i<m;i++)
27 {
28 dp[i+1]=dp[i]*dp[i]/n+(dp[i]+1.0)*(n-dp[i])/n;
29 }
30 printf("%.10f\n",dp[m]);
31 }
AC Code(probability):
1 // state expression:
2 // dp[i] = probability
3 // i: ith person got a gift
4 //
5 // find the answer:
6 // sigma dp[i]
7 //
8 // transferring:
9 // dp[i+1] = dp[i] * (1 - dp[i]) + (dp[i] - 1/n) * dp[i]
10 //
11 // boundary:
12 // dp[0] = 1
13 #include <iostream>
14 #include <stdio.h>
15 #include <string.h>
16 #define MAX_M 100005
17
18 using namespace std;
19
20 int n,m;
21 double ans=0;
22 double dp[MAX_M];
23
24 int main()
25 {
26 scanf("%d%d",&n,&m);
27 dp[0]=1;
28 for(int i=0;i<m;i++)
29 {
30 dp[i+1]=dp[i]*(1.0-dp[i])+(dp[i]-1.0/n)*dp[i];
31 ans+=dp[i];
32 }
33 printf("%.10f\n",ans);
34 }
AC Code(公式):
1 #include <iostream>
2 #include <stdio.h>
3 #include <string.h>
4 #include <math.h>
5
6 using namespace std;
7
8 int n,m;
9
10 int main()
11 {
12 scanf("%d%d",&n,&m);
13 printf("%.10f\n",n-n*pow((n-1.0)/n,m));
14 }