• CF865C Gotta Go Fast


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

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

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

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

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

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

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

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

    时间复杂度 (mathcal O (n imes T imes 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
    ", res);
    	return 0;
    }
    
  • 相关阅读:
    IO细述
    如何对HashMap按键值排序
    Java编程思想重点
    Java笔试题解答和部分面试题
    mysql优化
    MySQL 创建数据库并且指定编码
    JDBC 工具类
    JSP include标签和include指令
    SpingMVC ModelAttribute的用法
    Java 获取amr音频格式的音频长度
  • 原文地址:https://www.cnblogs.com/Ax-Dea/p/15234122.html
Copyright © 2020-2023  润新知