BZOJ P1419 Red is good
题目传送门
思路
状态设计
我们可以想象先把所有牌倒入一个袋子中,然后在一个一个取。
设 d p i , j dp_{i, j} dpi,j 表示目前袋中有【 i i i 个红牌】和【 j j j 个黑牌】。
状态转移
现在考虑从袋子中抓牌:
- 抓到的是红牌:
抓到红牌的概率是 i i + j \frac{i}{i + j} i+ji,抓后袋子中还剩下 i − 1 i - 1 i−1 个红牌和 j j j 个黑牌,那么抓到红牌的期望贡献就是 i i + j × ( d p i − 1 , j + 1 ) \frac{i}{i + j} \times (dp_{i - 1, j} + 1) i+ji×(dpi−1,j+1); - 抓到的是黑牌:
抓到黑牌的概率是 j i + j \frac{j}{i + j} i+jj,抓后袋子中还剩下 i i i 个红牌和 j − 1 j - 1 j−1 个黑牌,那么抓到红牌的期望贡献就是 j i + j × ( d p i , j − 1 + 1 ) \frac{j}{i + j} \times (dp_{i, j - 1} + 1) i+jj×(dpi,j−1+1)。 - 随时停止:因为有可以随时停止这一限制,所以在转移时,我们要将 d p i , j − 1 dp_{i, j - 1} dpi,j−1 和 d p i − 1 , j dp_{i - 1, j} dpi−1,j 与 0 0 0 取 m a x max max。因为再在剩下的牌中取时,期望已经是负数,所以取的话肯定更劣。与 0 0 0 取 m a x max max 就相当于是停止取牌。
因此总得转移方程就是:
d p i , j = i i + j × ( m a x ( d p i − 1 , j , 0 ) + 1 ) + j i + j × ( m a x ( d p i , j − 1 , 0 ) + 1 ) dp_{i, j} = \frac{i}{i + j} \times (max(dp_{i - 1, j}, 0) + 1) + \frac{j}{i + j} \times (max(dp_{i, j - 1}, 0) + 1) dpi,j=i+ji×(max(dpi−1,j,0)+1)+i+jj×(max(dpi,j−1,0)+1)
边界条件
当没有黑牌的时候, ∀ i ∈ [ 1 , n ] , d p i , 0 = i \forall i \in [1, n], \ dp_{i, 0} = i ∀i∈[1,n], dpi,0=i。
复杂度
- 时间复杂度 O ( n × m ) O(n \times m) O(n×m);
- 空间由于限制了 64 M B 64MB 64MB,所以要用滚动数组,最后为 O ( m ) O(m) O(m)。
代码
#include <bits/stdc++.h>using namespace std;const int maxn = 5e3 + 7;int n, m;
double dp[2][maxn];
int main() {scanf("%d%d", &n, &m); for (int i = 1; i <= n; ++i) {int now = i & 1, lst = (i - 1) & 1;dp[now][0] = i;for (int j = 1; j <= m; ++j) {dp[now][j] = (max(dp[lst][j], 0.0) + 1) * i / (i + j) + (max(dp[now][j - 1], 0.0) - 1) * j / (i + j);}}int x = dp[n & 1][m] * 1e6; // 不进位保留 6 位 小数printf("%.6lf\n", max(0.0, x * 1e-6));return 0;
}