zoukankan      html  css  js  c++  java
  • 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] = egin{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
    ", 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
  • 相关阅读:

    python内存管理
    python-继承类执行的流程
    Redis-key的设计技巧
    Redis-误操作尝试恢复
    Python3之hashlib
    面相对象
    设计模式
    RESTful API规范
    Django中间件执行流程
  • 原文地址:https://www.cnblogs.com/ww3113306/p/10206511.html
Copyright © 2011-2022 走看看