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;
}

浙公网安备 33010602011771号