题目来源:https://biancheng.love/contest-ng/index.html#/34/problems
题目描述
零崎在空闲时间很多的时候,就喜欢玩一些非常耗时间的游戏,比如可以死上几千次的I wanna,又比如一不小心就要重头开始的多米诺骨牌。
在摆放多米诺骨牌时,如果中途碰倒一块,就会产生雪崩般的影响。比如说11__1x11_11这种形状,零崎这么作死的人当然会在中间x位置放一枚骨牌……这种作死的做法有pl的概率会倒向左边并把左边的1个骨牌碰倒,或者有pr的概率会倒向右边并把右边的2个都碰倒。(骨牌不是量子态不会既左倒又右倒……)
现在零崎准备把手里的N枚多米诺骨牌摆成一条直线,那么他摆放骨牌次数的期望是多少?
输入
多组输入数据。
每组数据为三个数,第一个为整数N<10000,接下来两个浮点数pl,pr,0<pl+pr<1
输出
对于每组数据,输出一行,为采取最佳摆放方式时的次数期望,保留两位小数
输入样例
2 0.1 0.1
10 0.2 0.3
输出样例
2.66
44.03
Hint
几何分布的期望Ex=1/p
O(n^2)可过
代码:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define INF 0x3f3f3f3f const int N = 1000005; int n; double p, pl, pr, dp[N]; double cal(int l, int r) { return dp[l] + dp[r] + (pl * dp[l] + pr * dp[r] + 1) / p; } double solve() { p = 1 - pl - pr; dp[0] = 0; dp[1] = 1 / p; int pre = 0; for (int i = 2; i <= n; i++) { dp[i] = cal(pre, i - pre - 1); for (int j = pre + 1; j < i; j++) { int l = j, r = i - 1 - j; double tmp = cal(l, r); if (dp[i] >= tmp) { dp[i] = tmp; pre = j; } else break; } } return dp[n]; } int main() { while (~scanf("%d", &n) && n) { scanf("%lf%lf", &pl, &pr); printf("%.2lf ", solve()); } return 0; }