洛谷 P1654 OSU!
题目链接:洛谷 P1654 OSU!
算法标签: 期望DP
、动态规划(DP)
题目
题目描述
osu 是一款群众喜闻乐见的休闲软件。
我们可以把osu的规则简化与改编成以下的样子:
一共有(n)次操作,每次操作只有成功与失败之分,成功对应1,失败对应0,(n)次操作对应为1个长度为n的01串。在这个串中连续的 (X) 个 (1) 可以贡献 (X^3) 的分数,这x个1不能被其他连续的1所包含(也就是极长的一串1,具体见样例解释)
现在给出n,以及每个操作的成功率,请你输出期望分数,输出四舍五入后保留1位小数。
输入格式
第一行有一个正整数n,表示操作个数。接下去n行每行有一个[0,1]之间的实数,表示每个操作的成功率。
输出格式
只有一个实数,表示答案。答案四舍五入后保留1位小数。
输入输出样例
输入 #1
3
0.5
0.5
0.5
说明/提示
【样例说明】
000分数为0,001分数为1,010分数为1,100分数为1,101分数为2,110分数为8,011分数为8,111分数为27,总和为48,期望为48/8=6.0
N<=100000
题解:
期望(概率)DP
说实话没有直接写出来,也没学过期望DP,(承认自己偷看了一下题解),但是这道题如果耐心推一推式子还是很简单就可以理解的,那么过程如下:
因为题目中讲到连续的1可以贡献(X^3),那么我们来研究(X^3)这个式子,不难发现以下规律:
((x + 1)^3 = (x + 1)^2 imes (x + 1) => x^3 + 3x^2 + 3x + 1)
所以: ((x + 1)^3 - x^3 = 3x^2 + 3x + 1)
这样我们发现了什么,我们可以完全的用关于(x)的多项式来表示((x+1)),同理((x-1))也可以表示(x)。那么对于下一步,我们考虑处理出(x)与(x^2):
对于(x)的处理很简单,(x = (x-1) + 1 ~=>~ x_i = x_{i-1} + 1)
那么考虑(x^2),我们可以推出$(x+1)2=x2+2x+1 => x^2_i = x^2_{i-1} + 2 imes x_{i-1}+1 $
那么对于我们所求的(ans):
(ans_i = ans_{i-1} + (3 imes x^2_{i-1}+3 imes x_{i-1}+1))
因为这道题每一步都涉及到了概率(当前数位为1的概率),那么我们就在(x,x^2,ans)的表达式后边都乘上一个当前为概率(p[i]),题目得解。
AC代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
double p[N], x_1[N], x_2[N], ans[N], sum;
int n;
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i ++ )
{
scanf("%lf", &p[i]);
}
for (int i = 1; i <= n; i ++ )
{
x_1[i] = (x_1[i - 1] + 1) * p[i];
x_2[i] = (x_2[i - 1] + 2 * x_1[i - 1] + 1) * p[i];
ans[i] = ans[i - 1] + (3 * x_2[i - 1] + 3 * x_1[i - 1] + 1) * p[i];
}
printf("%.1lf
", ans[n]);
return 0;
}