像潮落潮涌,送我奔向自由。|

寂静的海底

园龄:3年2个月粉丝:59关注:15

【题解】CF865C 二分求期望

题意:

你是一个 up 主,你要录一段速通 RA2YR 的视频,

战役有 n 关,每关你有 pi% 的可能性花 Fi 的时间通过,(1pi)% 的可能性花掉 Si 的时间通过(失误了),其中保证 Fi>Si

但因为你想“速通”,你不希望你的视频长度超过 m

当你认为自己接下来可能录不完(接着录录完不如重新录)时,你会重新开始录,求录完整个游戏的时间期望。

思路:

首先不考虑时间限制,用 f(i) 表示打完前 i 关的期望时间,那么由期望的线性性易得转移方程为:

f(i)=f(i1)+pi×Fi+(1pi)×Si

然后考虑时间限制,那么打到第 i 关用时 a,b(a<b) 时打完的期望是不同的,(可能会重来)

所以为状态再加一维:f(i,j) 表示打过了第 i 关用时为 j 时打完的期望。

易知 f(n,j)=0,要求 f(0,0),每一位都有其后一位有关,所以是由 n 倒推至 0

转移方程为:

f(i,j)={0,i=n,jmf(0,0),j>mmin(f(0,0),e1+e2),otherwise.

其中 e1=pi+1×f(i+1,j+fi+1)+fi+1))

e2=pi+1×(1pi+1)×(f(i+1,j+Si+1)+Si+1)

f(0,0) 表示回到最开始重新打(如果重新打的期望已经比现在更优就重新打,如果超过 m 也要重新从头开始),

其余部分和正常求期望相同。

现在就出现了问题:这不是一个 dp,它的转移有环,转移关系如图 :

f(0,0) 决定着每一个 f 值,又要由其它 f 值得到,形成了环。

那么应该怎么处理环呢?

显然,每个未知 f 值都对应一个转移,也就是说这些转移形成了一个由 m×n+1 个方程,m×n+1 个未知数组成的方程组。

所以我们似乎可以使用高斯消元?

O(n3m3) 的复杂度很明显不能接受,而且 min 函数的存在会让消元变得复杂。

分析发现造成这些环的”罪魁祸首“都是 f(0,0) ,把 f(0,0) 看作常数,那么就可以无环转移,怎么转移呢?

使用 dp!

很显然我们需要找到正确的停下时间,因为最优重开时间一定是等于期望时间的,并且显然由单调性,所以二分停下的时间即可。

//dp[i][j]=(dp[i+1][j+a[i]]+a[i])*p[i]+(p[i+1][j+b[i]]+b[i])*(1-p[i])
#include<bits/stdc++.h>
#define eps 0.00000000002
using namespace std;
long double f[52][50002];int a[5003],b[5300],p[5300];
int n,m;
bool check(long double v)
{
    f[n][0]=0.000000;
    for(int i=n-1;i>=0;--i)
      {
        for(int j=m+1;j<=5002;++j)
          f[i+1][j]=v;
        for(int j=0;j<=m;++j)
           f[i][j]=min(v,(f[i+1][j+a[i+1]]+a[i+1])*p[i+1]/100.0+(f[i+1][j+b[i+1]]+b[i+1])*(100.0-p[i+1])/100.0);
      }
    return f[0][0]<v; 
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;++i)
      cin>>a[i]>>b[i]>>p[i];
    long double l=0,r=1e9,ans=-1.000;
    int cnt=0;
    while(r-l>eps)
     {
        cnt++;
        if(cnt-200>0)break;
        long double mid=(l+r)/2.00;
        if(check(mid)) ans=mid,r=mid-eps;
        else l=mid+eps;
     }
     printf("%.9Lf",ans);
}

Solution By : ღꦿ࿐(kk)

Image & Stuff By:black_trees

posted @   寂静的海底  阅读(5)  评论(0编辑  收藏  举报  
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起