【题解】CF865C 二分求期望
题意:
你是一个 up 主,你要录一段速通 RA2YR 的视频,
战役有 关,每关你有 的可能性花 的时间通过, 的可能性花掉 的时间通过(失误了),其中保证 。
但因为你想“速通”,你不希望你的视频长度超过 。
当你认为自己接下来可能录不完(接着录录完不如重新录)时,你会重新开始录,求录完整个游戏的时间期望。
思路:
首先不考虑时间限制,用 表示打完前 关的期望时间,那么由期望的线性性易得转移方程为:
然后考虑时间限制,那么打到第 关用时 时打完的期望是不同的,(可能会重来)
所以为状态再加一维: 表示打过了第 关用时为 时打完的期望。
易知 ,要求 ,每一位都有其后一位有关,所以是由 倒推至 。
转移方程为:
其中 。
。
表示回到最开始重新打(如果重新打的期望已经比现在更优就重新打,如果超过 也要重新从头开始),
其余部分和正常求期望相同。
现在就出现了问题:这不是一个 dp,它的转移有环,转移关系如图 :
决定着每一个 值,又要由其它 值得到,形成了环。
那么应该怎么处理环呢?
显然,每个未知 值都对应一个转移,也就是说这些转移形成了一个由 个方程, 个未知数组成的方程组。
所以我们似乎可以使用高斯消元?
的复杂度很明显不能接受,而且 函数的存在会让消元变得复杂。
分析发现造成这些环的”罪魁祸首“都是 ,把 看作常数,那么就可以无环转移,怎么转移呢?
使用 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
本文已经结束了。本文作者:ღꦿ࿐(DeepSea),转载请注明原文链接:https://www.cnblogs.com/Dreamerkk/p/17970993,谢谢你的阅读或转载!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步