CF865C Gotta Go Fast 题解

考虑二分答案然后 dp,钦定 \(mid\) 为重新开始的期望时间。若求出的期望时间 \(<mid\) 小,则答案 \(<mid\)

\(f_{i,j}\) 表示当前到了第 \(i\) 关,用了 \(j\) 单位时间通关需要花费的的期望总时间。考虑怎么转移:

  • \(j>R\),则必须重启,\(f_{i,j}=j+mid\)
  • \(j\le R\),则 \(f_{i,j}=\min(j+mid,\frac{p_i}{100}f_{i+1,j+a_i}+(1-\frac{p_i}{100})f_{i+1,j+b_i})\)

比较 \(f_{1,0}\)\(mid\) 即可。时间复杂度 \(\mathcal O(nR\log V)\)

参考代码:

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define rept(i,a,b) for(int i=(a);i<(b);++i)
#define drep(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
int n,s,sm,a[53],b[53],p[53];
long double l,r,f[53][5003];
bool check(long double mid){
	rep(i,0,sm)f[n+1][i]=i>s?i+mid:i;
	drep(i,n,1){
		rep(j,0,sm){
			f[i][j]=j>s?j+mid:min(j+mid,p[i]/100.0*f[i+1][j+a[i]]+(1-p[i]/100.0)*f[i+1][j+b[i]]);
		}
	}
	return f[1][0]<mid;
}
signed main(){
	scanf("%d%d",&n,&s);
	rep(i,1,n)scanf("%d%d%d",&a[i],&b[i],&p[i]),sm+=b[i];
	r=1e9;
	while(l+1e-11<r){
		long double mid=(l+r)/2;
		if(check(mid))r=mid;
		else l=mid;
	}
	printf("%.10Lf",l);
	return 0;
}
posted @ 2025-07-11 21:07  zifanwang  阅读(7)  评论(0)    收藏  举报