• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

CF865CGottaGoFast

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

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

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

发现重开时候期望时间越大必然导致了最后通关时间变长,所以可以用二分答案加上一个 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;
}

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
Go Error 嵌套到底是怎么实现的?发布时间:2022-07-10
下一篇:
Go基础系列:接口类型断言和type-switch发布时间:2022-07-10
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap