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 }

 

posted @ 2017-09-21 01:54  Leohh  阅读(196)  评论(0编辑  收藏  举报