• codeforces gym 103049G Great Expectations


    题意:

    一个游戏如果不出意外会花 $n(<=5000)$个时间完成,世界纪录是$r(<=5000)$,有$m(<=50)$种可能发生的意外情况浪费时间。

    意外情况格式如下:

    $t(<n)$  $p(0<p<1)$  $d$($<=1000$) 三个数,表示该事件发生在正常流程下的第$t$秒时,发生概率为$p$,浪费$d$的时间。

    你可以随时重新开始游戏,问从一开始玩到成功打破记录(一局游戏从开始到结束时间小于$r$)期望一共花多少时间。

    首先按照期望类题的套路,倒推状态转移,我们设$F[i][j]$为进行到正常流程下第$i$秒,实际本次尝试已经花了$j$秒还期望花多少时间突破记录。显然,答案就是$F[0][0]$

    下面就是写转移方程,由于意外事件很少,我们将$F[i][j]$的意义改为已经进行到了第$i$个意外时间刚开始的时间,本次尝试已经花费了$j$秒且不知道这次事件是否会发生的期望剩余时间。得到如下转移方程:

    $F[i][j]=(1-p[i])*(F[i+1][j+t[i+1]-t[i]]+t[i+1]-t[i])+p[i]*min(F[0][0],F[i+1][j+d[i]+t[i+1]-t[i]]+d[i]+t[i+1]-t[i]) (j+d[i]+n-t[i]<r)$

    $F[i][j]=(1-p[i])*(F[i+1][j+t[i+1]-t[i]]+t[i+1]-t[i])+p[i]*F[0][0]   (j+d[i]+n-t[i]>=r)$

    但是我们发现我们的转移方程出现了$F[0][0]$,而$F[0][0]$又是我们的最终答案,这就陷入了一个死环。当时训练的时候想到这一步就懵了,以为最后是要解方程,但是$min$又限制了我们无法通过解方程来得到答案。


    看了题解之后才顿悟,既然$F[0][0]$未知,我们能不能尝试去二分$F[0][0]$,转移是用二分值,之后通过比较它与算出的$F[0][0]$的大小确定该调大还是调小。如果二分值大于$F[0][0]$,就意味着在一些决策点我们本应该选择重来但是我们选择了继续打,所以应当将二分值调小;如果小于$F[0][0]$,就意味着一些本应该继续打的地方我们选择了重来,所以应当将二分值调大。

     1 #include<iostream>
     2 #include<cstdlib>
     3 #include<cstdio>
     4 #include<cstring> 
     5 #include<cmath>
     6 #include<algorithm>
     7 #define N 5005
     8 #define double long double
     9 using namespace std;
    10 int n,r,m;
    11 int T[N];
    12 double P[N];
    13 int D[N];;
    14 double F[55][N];
    15 bool check(double X)
    16 {
    17     for(int i=m;i>=0;i--)
    18     {
    19         for(int j=T[i];j<r-(n-T[i]);j++)
    20         {
    21             F[i][j]=P[i]*(T[i+1]-T[i]+F[i+1][j+T[i+1]-T[i]]);
    22             if(j+D[i]+(n-T[i])<r)
    23             {
    24                 F[i][j]+=(1.0-P[i])*min(X,D[i]+T[i+1]-T[i]+F[i+1][D[i]+T[i+1]-T[i]+j]);
    25             }
    26             else
    27             {
    28                 F[i][j]+=(1.0-P[i])*X;
    29             }
    30         }
    31     }
    32     return X>F[0][0];
    33 }
    34 int main()
    35 {
    36     scanf("%d%d%d",&n,&r,&m);
    37     for(int i=1;i<=m;i++)
    38     {
    39         scanf("%d%Lf%d",&T[i],&P[i],&D[i]);
    40     }
    41     T[m+1]=n;
    42     P[0]=1;
    43     double li=0,ri=1e17,mid,ans;
    44     while(fabs(ri-li)>=1e-8)
    45     {
    46         mid=(li+ri)/2.0;
    47         if(check(mid)) ri=mid-(1e-8),ans=mid;
    48         else li=mid+(1e-8);
    49     }
    50     printf("%.10Lf
    ",ans);
    51     return 0;
    52 }
    53  
    View Code
  • 相关阅读:
    Leetcode#104 Maximum Depth of Binary Tree
    Leetcode#102 Binary Tree Level Order Traversal
    js 实时显示字数
    js获取链接参数
    DIV+CSS左右列高度自适应问题
    css 背景透明,文字不透明
    css position的值
    从头搭建vue项目
    vuejs怎么在服务器部署?
    windows下nginx安装、配置与使用
  • 原文地址:https://www.cnblogs.com/liutianrui/p/14806237.html
Copyright © 2020-2023  润新知