题目描述
osu 是一款群众喜闻乐见的休闲软件。
我们可以把osu的规则简化与改编成以下的样子:
一共有n次操作,每次操作只有成功与失败之分,成功对应1,失败对应0,n次操作对应为1个长度为n的01串。在这个串中连续的 X个1可以贡献X^3 的分数,这x个1不能被其他连续的1所包含(也就是极长的一串1,具体见样例解释)
现在给出n,以及每个操作的成功率,请你输出期望分数,输出四舍五入后保留1位小数。
输入格式
第一行有一个正整数n,表示操作个数。
接下去n行每行有一个[0,1]之间的实数,表示每个操作的成功率。
输出格式
只有一个实数,表示答案。答案四舍五入后保留1位小数。
样例
样例输入
3
0.5
0.5
0.5
样例输出
6.0
数据范围与提示
000分数为0,001分数为1,010分数为1,100分数为1,101分数为2,110分数为8,011分数为8,111分数为27,总和为48,期望为48/8=6.0
N<=100000
很显然啊,没推出来
(同Elaina进行了激烈的讨论,未果,遂看题解)
既然看了题解,那么就说说过程
比较容易想到的就是利用dp(思想)我们令f[i]为前i位的期望之和,很显然,对于第i位,会有1和0两种选择:
0的话就可以直接从前面(f[i-1])继承
1的话,就比较难办,因为我不知道从尾部开始连续1字串的长度,所以我就想去记录一下长度,但又一想,情况多了去了,怎么记录,况且概率各不相同,然后就卡住了(实际上我还想去预处理出\(x^{3}\)的,但被Elaina悬崖勒马了),最后看题解去了
开始正题
我们先不从3次方开始,先从一次的开始,对于第i位选1的期望值,那么会有
\(x^{1}[i]=(x^{1}[i-1]+1)*p[i]\)
那么对于二次的呢
根据公式:\((x+1)^{2}=x^{2}+2x+1\)
可知:
\(x^{2}[i]=(x^{2}[i-1]+2*x^{1}[i-1]+1)*p[i]\)
那么三次的也就有了
根据公式:\((x+1)^{3}=x^{3}+3x^{2}+3x^{1}+1\)
可知:
\(x^{3}[i]=(x^{3}[i-1]+3*x^{2}[i-1]+3*x^{1}[i-1]+1)*p[i]\)
到这里就有一个问题,为什么仅用算1的情况,那0呢?
实际上,根据上面的口胡,会发现,当选中1时,采用上面的公式,但对于0的话,它没有任何作用,也就是说,它可以直接从\(x^{3}[i-1]\)转移过来
因此,本题的真正转移方程实际是
\(x^{3}[i]=(x^{3}[i-1]+3*x^{2}[i-1]+3*x^{1}[i-1]+1)*p[i]+x^{3}[i-1]*(1-p[i])\)
实际上一开始看到这我还是有疑问,那对于1,0夹杂的情况呢,后面才发现自己想多了,在转移的时候都已经包含进去了
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+100;
int n;
double f[N],p[N],x1[N],x2[N];
int cnt=0;
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>p[i];
for(int i=1;i<=n;i++){
x1[i]=(x1[i-1]+1)*p[i];
x2[i]=(x2[i-1]+2*x1[i-1]+1)*p[i];
f[i]=(f[i-1]+3*x2[i-1]+3*x1[i-1]+1)*p[i]+f[i-1]*(1-p[i]);
}
cout<<setprecision(1)<<fixed<<f[n]<<endl;
}
最后贴一张深有感触的图