【题解】CF865C 二分求期望
题意:
你是一个 up 主,你要录一段速通 RA2YR 的视频,
战役有 $n$ 关,每关你有 $p_i\%$ 的可能性花 $F_i$ 的时间通过,$(1-p_i)\%$ 的可能性花掉 $S_i$ 的时间通过(失误了),其中保证 $F_i>S_i$。
但因为你想“速通”,你不希望你的视频长度超过 $m$。
当你认为自己接下来可能录不完(接着录录完不如重新录)时,你会重新开始录,求录完整个游戏的时间期望。
思路:
首先不考虑时间限制,用 $f(i)$ 表示打完前 $i$ 关的期望时间,那么由期望的线性性易得转移方程为:
$$ f(i)=f(i-1)+p_i \times F_i+(1-p_i)\times S_i $$
然后考虑时间限制,那么打到第 $i$ 关用时 $a,b(a<b)$ 时打完的期望是不同的,(可能会重来)
所以为状态再加一维:$f(i,j)$ 表示打过了第 $i$ 关用时为 $j$ 时打完的期望。
易知 $f(n,j)=0$,要求 $f(0,0)$,每一位都有其后一位有关,所以是由 $n$ 倒推至 $0$。
转移方程为:
$$ f(i,j)=\begin{cases} 0 ,& i=n,j\le m\\ f(0,0),& j >m \\ \min(f(0,0),e1+e2) ,& \text{otherwise.} \end{cases} $$
其中 $ e_1=p_{i+1} \times f(i+1,j+f_{i+1})+f_{i+1})) $。
$e_2=p_{i+1}\times(1-p_{i+1})\times(f(i+1,j+S_{i+1})+S_{i+1})$ 。
$f(0,0)$ 表示回到最开始重新打(如果重新打的期望已经比现在更优就重新打,如果超过 $m$ 也要重新从头开始),
其余部分和正常求期望相同。
现在就出现了问题:这不是一个 dp,它的转移有环,转移关系如图 :
$f(0,0)$ 决定着每一个 $f$ 值,又要由其它 $f$ 值得到,形成了环。
那么应该怎么处理环呢?
显然,每个未知 $f$ 值都对应一个转移,也就是说这些转移形成了一个由 $m\times n+1$ 个方程,$m\times n+1$ 个未知数组成的方程组。
所以我们似乎可以使用高斯消元?
$\text{O}(n^3 m^3)$ 的复杂度很明显不能接受,而且 $\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
本文已经结束了。本文作者:ღꦿ࿐(DeepSea),转载请注明原文链接:https://www.cnblogs.com/Dreamerkk/p/17970993,谢谢你的阅读或转载!