[bzoj1419]Red is good 题解
[bzoj1419]Red is good 题解
我真的是服了,没想到被一个 不能四舍五入 给坑惨了。
推导
因为指派是线性排放,很容易想到线性DP。设 \(dp_{i,j}\) 表示取了 \(i\) 个红牌,\(j\) 个黑牌的期望。
对于 \(dp_{i,j}\),很容易想到有两种:
- 上一个拿了一个红牌:值为 \(dp_{i - 1,j} + 1\),概率为 \(\frac{i}{i + j}\)。
- 上一个拿了一个黑牌:值为 \(dp_{i,j - 1} - 1\),概率为 \(\frac{j}{i + j}\)。
所以推导公式为:
\[dp_{i,j} = (dp_{i - 1,j} + 1) \times \frac{i}{i + j} + (dp_{i,j - 1} - 1) \times \frac{j}{i + j}
\]
因为是在最优情况下,所以当 \(dp_{i,j} < 0\) 时,令 \(dp_{i,j} = 0\)。
下面开始头疼的环节:如何不四舍五入?其实并不难,但是被精度卡就很难受。
代码放上,祥建注释:
void print(double printion) {
long long fixing = printion * 1000000 * 10; // 1000000取出后6位,再×10取出判断四舍五入的一位(注意开long long,卡了我30min)
fixing = (fixing - fixing % 10) / 10; // 删去判断四舍五入的一位
double ans = fixing * 1.0 / 1000000; // 直接除就可以了
printf("%.6lf", ans); // printf
}
举个例子:41.666666666...
-
四舍五入:41.666667
-
我的输出:41.666666
第一步,fixing = 416666666;
第二步,fixing = (416666666 - 416666666 % 10) / 10 = 41666666;
第三步,ans = 41666666 * 1.0 / 1000000 = 41.666666。
代码
#include <bits/stdc++.h>
#define Maxn 5005
using namespace std;
int n, m; // n -- Red;m -- Black
double dp[3][Maxn];
void print(double printion) {
long long fixing = printion * 1000000 * 10;
fixing = (fixing - fixing % 10) / 10;
double ans = fixing * 1.0 / 1000000;
printf("%.6lf", ans);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i ++) {
dp[1][0] = i;
for (int j = 1; j <= m; j ++) {
dp[1][j] = (dp[0][j] + 1) * i * 1.0 / (i + j) + (dp[1][j - 1] - 1) * j * 1.0 / (i + j);
if (dp[1][j] < 0.0) { dp[1][j] = 0.0; }
} for (int j = 1; j <= m; j ++) {
dp[0][j] = dp[1][j];
}
}
// print(41.66666666666);
print(dp[1][m]);
return 0;
}
由于内存只有 \(64MB\),我还用了一个 轮换数组(自己编的名字),就是将两行轮换使用,节省内存。

浙公网安备 33010602011771号