洛谷 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 \times (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=x^2+2x+1 ~=>~ x^2_i = x^2_{i-1} + 2 \times x_{i-1}+1 $
那么对于我们所求的\(ans\):
\(ans_i = ans_{i-1} + (3 \times x^2_{i-1}+3 \times 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\n", ans[n]);
return 0;
}