[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\),我还用了一个 轮换数组(自己编的名字),就是将两行轮换使用,节省内存。

posted @ 2024-08-07 16:26  BLM-dolphin  阅读(33)  评论(0)    收藏  举报