CF2181J Jinx or Jackpot 题解

CF2181J Jinx or Jackpot 题解

这道题首先拿到后首先可以猜一下,肯定一开始先用 0 块钱试试概率,然后因为杰克知道 \(p_i\) 为多少,所以可以推测出下一次的概率,然后直接梭哈。

固定 \(p_i\),我们假设前面赢了 \(a\) 次,输了 \(b\) 次,那么概率肯定是 \(p_i^a(1-p_i)^b\). 那么对于所有的,概率就一定是:

\[\frac{\binom{a + b}{a}\sum\limits_ip_i^a(1-p_i)^b}{n} \]

于是当我们已经赢了 \(a\) 次,输了 \(b\) 次后,利用贝叶斯公式:

\[\operatorname{P}(\text{A}|\text{B})=\frac{\operatorname{P}(\text{B}|\text{A})\operatorname{P}(\text{A})}{\operatorname{P}(\text{B})} \]

这里 \(\text{B}\) 指已经赢了 \(a\) 次,输了 \(b\) 次后,\(\text{A}\) 指又赢了一次,那么我们另 \(\operatorname{p}(a,b)\) 表示赢了 \(a\) 次,输了 \(b\) 次后,再赢一次的概率,则

\[\operatorname{p}(a,b) = \frac{\binom{a +b}{a}\sum\limits_ip_i^{a+1}(1-p_i)^b}{\binom{a+b}{a}\sum\limits_ip_i^a(1-p_i)^b}=\frac{\sum\limits_ip_i^{a+1}(1-p_i)^b}{\sum\limits_ip_i^a(1-p_i)^b} \]

那么我们可以定义dp转移时,令 \(dp_{a,b}\) 表示已经赢了 \(a\) 场和输了 \(b\) 场的,接下来期望的余额,那么

\[dp_{a,b}=\max\{\operatorname{p}(a,b)dp_{a + 1, b}+(1-\operatorname{p}(a,b))dp_{a, b+ 1},2\operatorname{p}(a,b)dp_{a + 1, b}\} \]

那么如果 \(a+b=k\) 那么令 \(dp_{a,b}=1\) ,然后最后答案是 \(1000(dp_{0,0}-1)\)

代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 100000 + 5;
const int K = 30 + 5;
long double p[N];
long double prob[K][K], pw1[N][K], pw2[N][K], dp[K][K];
int main() {
    int n, k;
    cin >> n >> k;
    for (int i = 1; i <= n; i++) {
        int x;
        cin >> x;
        p[i] = 1.0 * x / 100;
        pw1[i][0] = pw2[i][0] = 1;
        for (int j = 1; j <= k + 1; j++) {
            pw1[i][j] = pw1[i][j - 1] * p[i];
            pw2[i][j] = pw2[i][j - 1] * (1 - p[i]);
        }
    }   
    for (int i = 0; i <= k; i++) {
        for (int j = 0; j <= k - i; j++) {
            long double up = 0, down = 0;
            for (int x = 1; x <= n; x++) {
                up += pw1[x][i + 1] * pw2[x][j];
                down += pw1[x][i] * pw2[x][j];
            }
            if (down != 0)
                prob[i][j] = up / down;
        }
    }
    for (int len = k; len >= 0; len--) {
        for (int i = 0; i <= len; i++) {
            int j = len - i;
            if (len == k) {
                dp[i][j] = 1;
            }
            else {
                dp[i][j] = max(prob[i][j] * dp[i + 1][j] + (1 - prob[i][j]) * dp[i][j + 1], 2 * prob[i][j] * dp[i + 1][j]);
            }
        }
    }
    printf("%.6Lf", 1000 * (dp[0][0] - 1));
    return 0;
}
posted @ 2026-09-10 10:50  MikotoHohenz  阅读(17)  评论(0)    收藏  举报