CF623D birthday 贪心 概率期望


题意:n个人,玩抓人游戏,每抓住一个人都要猜这个人是谁。对于每一局,第i个人有$p_{i}$的概率被抓到。游戏结束当且仅当每个人都在某局中被抓到并且猜中自己的名字,求一个合适的策略来使得期望游戏局数最少,输出这个期望最少局数.
题解:设$g[i]$表示到$i$局为止,已经全部被猜中过的概率,$f[i][x]$表示到第$i$局为止,已经猜中过第$x$个人的概率。
那么有$$ans = \sum_{i = 1}^{\infty} (g[i] - g[i - 1])i$$
随游戏局数增长,$g[x]$会趋近于1,要让期望最小,显然在$x$越小时,要让$g[x] - g[x - 1]$越大越好,即$g[x]$增长的越快越好。
若在第$i$局猜被抓到的是$k$,那么有:
$f[i][x] = \begin{cases}
f[i - 1][x] + (1 - f[i - 1][x]) p_{x} \quad x == k\\
f[i - 1][x] \quad x != k
\end{cases}$
$g[x] = g[x - 1] \frac{f[x][k]}{f[x - 1][k]}($因为只有$f[x][k]$变化了)
因此我们只需要让$\frac{f[x][k]}{f[x - 1][k]}$最大即可。
$$\frac{f[x][k]}{f[x - 1][k]} = \frac{f[x - 1][k] + (1 - f[x - 1][k])p_{k}}{f[x - 1][k]} = 1 + \frac{(1 - f[x - 1][k])p_{k}}{f[x - 1][k]}$$
所以要使$\frac{(1 - f[x - 1][k])p_{k}}{f[x - 1][k]}$最大。
因此我们枚举$k$,贪心的找最优策略并更新答案,大约$3e5$次可以满足精度要求

这里注意为了满足初始化的要求(在没有把n个人都猜过之前,是没有概率全部猜中的),所以要在最开始先把n个人都猜一遍,然后再继续贪心

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define R register int
 4 #define AC 110
 5 #define ld double 
 6 
 7 int n;
 8 ld ans, last, g;
 9 ld f[AC], p[AC];
10 
11 inline int read()
12 {
13     int x = 0;char c = getchar();
14     while(c > '9' || c < '0') c = getchar();
15     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
16     return x;
17 }
18 
19 ld cal(int x){
20     return f[x] + 1.0 * (1 - f[x]) * p[x];
21 }
22 
23 void pre()
24 {
25     n = read(), last = 1;
26     for(R i = 1; i <= n; i ++) 
27         f[i] = p[i] = 1.0 * read() / 100.0, last *= p[i];//根据转移式来的
28     ans = n * last;//因为只有猜过所有人之后才有可能结束游戏。。。
29 }
30 
31 /*        int x = 0; ld maxn = 0;
32         for(R j = 1; j <= n; j ++)
33         { 
34             ld now = cal(j);
35             if(cal(j) / f[j] > maxn) maxn = now, x = j; 
36         }    */
37 void work()//为了解决初始化问题,,,先把所有人都猜一遍
38 {
39     for(R i = n + 1; i <= 300000; i ++)
40     {
41         int x = 1; //x不能默认为1,不然f[x]就为0了,,,,
42         for(R j = 1; j <= n; j ++)
43             if(cal(j) / f[j] > cal(x) / f[x]) x = j; 
44         g = last * cal(x) / f[x], f[x] = cal(x);
45         ans += i * (g - last), last = g;
46     }
47     printf("%.10lf\n", ans);
48 }
49 
50 int main()
51 {
52     freopen("in.in", "r", stdin);
53     pre();
54     work();
55     fclose(stdin);
56     return 0;
57 }
View Code

 

posted @ 2019-01-01 23:06  ww3113306  阅读(379)  评论(0编辑  收藏  举报
知识共享许可协议
本作品采用知识共享署名-非商业性使用-禁止演绎 3.0 未本地化版本许可协议进行许可。