Codeforces 865C Gotta Go Fast 二分 + 期望dp (看题解)

第一次看到这种骚东西, 期望还能二分的啊???

因为存在重置的操作, 所以我们再dp的过程中有环存在。

为了消除环的影响, 我们二分dp[ 0 ][ 0 ]的值, 与通过dp得出的dp[ 0 ][ 0 ]的值进行比较。

这样看着好像很不合理, 但实际上比较这两个值, 你能推倒出当前二分的值合不合法。

#include<bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define mk make_pair
#define PLL pair<LL, LL>
#define PLI pair<LL, int>
#define PII pair<int, int>
#define SZ(x) ((int)x.size())
#define ull unsigned long long

using namespace std;

const int N = 1e5 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
const double PI = acos(-1);

int n, R, F[N], S[N], up;
double P[N];
double dp[50 + 7][50 * 100 + 7];

double dfs(int i, int j, double x) {
    if(i == n) {
        if(j <= R) return 0;
        else return x;
    }
    if(dp[i][j] + eps > 0) return dp[i][j];
    double T1 = P[i + 1] * (dfs(i + 1, j + F[i + 1], x) + F[i + 1]) + (1 - P[i + 1]) * (dfs(i + 1, j + S[i + 1], x) + S[i + 1]);
    dp[i][j] = min(T1, x);
    return dp[i][j];
}

bool check(double x) {
    for(int i = 0; i <= n; i++)
        for(int j = 0; j <= up; j++)
            dp[i][j] = -1;
    if(dfs(0, 0, x) < x) return true;
    else return false;
}
int main() {
    scanf("%d%d", &n, &R);
    for(int i = 1; i <= n; i++) {
        scanf("%d%d%lf", &F[i], &S[i], &P[i]);
        P[i] /= 100;
        up += S[i];
    }
    double low = n, high = 5e8;
    for(int o = 1; o <= 100; o++) {
        double mid = (low + high) / 2;
        if(check(mid)) high = mid;
        else low = mid;
    }
    printf("%.12f\n", (low + high) / 2);
    return 0;
}

/*
*/

猜你喜欢

转载自www.cnblogs.com/CJLHY/p/10586116.html