CF865C Gotta Go Fast

时间:2021-09-06
本文章向大家介绍CF865C Gotta Go Fast,主要包括CF865C Gotta Go Fast使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

发现这个重开操作十分鬼畜,活生生将每一个状态和初始状态连了一条边。

由于每次重开肯定是使得本次通过关卡的时间增多,所以最优的情况一定是这次一定必然比期望时间多时才重开,也就是说,最优的情况一定是重开时候的期望和最终的期望相同。

发现重开时候期望时间越大必然导致了最后通关时间变长,所以可以用二分答案加上一个 DP 解决。

\(f_{i, j}\) 表示现在在完成了前面 \(i\) 个任务点,已经花了 \(j\) 时间,还需要的时间期望值,有转移:

\[f_{i, j} = p_{i + 1} \times (f_{i + 1, j + F_{i + 1}} + F_{i + 1}) + (1 - p_{i + 1}) \times (f_{i + 1, j + S_{i + 1}} + S_{i + 1}) \]

重开的转移只在 \(i > 0\) 时存在:

\[f_{i, j} = \min(f_{i, j}, mid) \]

其中 \(mid\) 是二分的答案。

时间复杂度 \(\mathcal O (n\times T \times \log A)\)

#include <bits/stdc++.h>
#define forn(i,s,t) for(register int i=(s); i<=(t); ++i)
#define form(i,s,t) for(register int i=(s); i>=(t); --i)
#define rep(i,s,t) for(register int i=(s); i<(t); ++i)
using namespace std;
typedef double f64;
const int N = 103, M = 100 * 103;
int n, m, F[N], S[N], p[N], pre[N], sumF, sumS; f64 f[N][M];
inline bool check(f64 mid) {
	memset(f, 0, sizeof f);
	forn(i,m + 1,sumS) f[n][i] = mid;
	form(i,n - 1,0) forn(j,0,pre[i]) {
		f[i][j] = 1.0 * p[i + 1] / 100 * (f[i + 1][j + F[i + 1]] + F[i + 1]) + 1.0 * (100 - p[i + 1]) / 100 * (f[i + 1][j + S[i + 1]] + S[i + 1]);
		if(i) f[i][j] = min(f[i][j], mid);
	}
	return f[0][0] <= mid;
}
int main() {
	scanf("%d%d", &n, &m);
	forn(i,1,n) scanf("%d%d%d", F + i, S + i, p + i), sumF += F[i], sumS += S[i], pre[i] = pre[i - 1] + S[i];
	f64 l = 0, r = 1e8, res = 1e3, mid;
	while(r - l > 1e-8) {
		mid = (l + r) * 0.5;
		if(check(mid)) r = mid, res = mid;
		else l = mid;
	}
	printf("%.7lf\n", res);
	return 0;
}

原文地址:https://www.cnblogs.com/Ax-Dea/p/15234122.html