洛谷P10504 守卫者的挑战 题解 概率DP

题目链接:https://www.luogu.com.cn/problem/P10504

状态 \(f_{i, s, k}\) 表示:

  • 当前正面临第 \(i\) 项挑战(此时第 \(1 \sim i-1\) 项挑战已完成,第 \(i\) 项挑战还没开始);
  • 目前已经挑战成功了 \(s\) 项(即第 \(1 \sim i-1\) 项挑战中共有 \(s\) 项挑战成功,\((i-1)-s\) 项没挑战成功);
  • 此时的背包容量剩余 \(k\)(实际实现时加了一个 \(210\) 的偏移)。

边界条件时 \(i = n+1\),此时第 \(1\)\(i-1 = n\) 项挑战均已挑战完成。

此时若 \(s \ge L\)(至少挑战成功 \(L\) 次) 且 \(k \ge 0\)(背包足够装所有的地图残片),则获胜的概率为 \(1\);否则,获胜的概率为 \(0\)

非边界情况下:

\(f_{i, s, k}\)\(p_i\) 的概率转移到 \(f_{i+1, s+1, k + a_i}\),有 \(1 - p_i\) 的概率转移到 \(f_{i+1, s, k}\),所以:

\[f_{i, s, k} = p_i \times f_{i+1, s+1, k + a_i} + (1 - p_i) \times f_{i+1, s, k} \]

示例程序:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 220;
bool vis[maxn][maxn][maxn*2];
double f[maxn][maxn][maxn*2];
int n, L, K, a[maxn];
double p[maxn];

// 当前在第 i 局,目前已经赢了 s 局,剩余背包容量为 k
double dfs(int i, int s, int k) {
    k = min(k, maxn*2-1);
    if (i == n+1) {
        return k >= 210 && s >= L ? 1 : 0;
    }
    if (vis[i][s][k])
        return f[i][s][k];
    vis[i][s][k] = true;
    return f[i][s][k] = p[i] * dfs(i+1, s+1, k + a[i]) + (1 - p[i]) * dfs(i+1, s, k);
}

int main() {
    cin >> n >> L >> K;
    for (int i = 1; i <= n; i++) {
        cin >> p[i];
        p[i] /= 100.0;
    }
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    double res = dfs(1, 0, K + 210); // 初始背包容量为 K
    printf("%.6lf\n", res);
    return 0;
}
posted @ 2024-09-12 22:54  quanjun  阅读(4)  评论(0编辑  收藏  举报