SGU 495 Kids and Prizes:期望dp / 概率dp / 推公式
题目链接: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 }