#3805 OSU!
题面
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
SOL
最开始我们可能会去考虑一个O(N^2)的转移:
f
[
i
]
[
j
+
1
]
=
f
[
i
]
[
j
]
+
(
(
j
+
1
)
3
−
j
3
)
∗
p
[
i
]
;
f[i][j+1]=f[i][j]+((j+1)^3-j^3)*p[i];
f[i][j+1]=f[i][j]+((j+1)3−j3)∗p[i];
但是,如果这样做,空间可以用滚动数组优化,但是时间怎么过?
其实如果我们注意到每次变化的值:
(
(
j
+
1
)
3
−
j
3
)
即
3
∗
j
2
+
3
∗
j
+
1
((j+1)^3-j^3)即3*j^2+3*j+1
((j+1)3−j3)即3∗j2+3∗j+1
您或许可以意识到,维护这个变化的值就可以了
设f[i]为前i次操作的答案,
x
1
[
i
]
为
x
,
x
2
[
i
]
为
x
2
x1[i]为x,x2[i]为x^2
x1[i]为x,x2[i]为x2
于是就有
x
1
[
i
]
=
(
x
1
[
i
−
1
]
+
1
)
∗
p
[
i
]
,
x
2
[
i
]
=
(
x
2
[
i
−
1
]
+
x
1
[
i
−
1
]
∗
2
+
1
)
∗
p
[
i
]
x1[i]=(x1[i-1]+1)*p[i],x2[i]=(x2[i-1]+x1[i-1]*2+1)*p[i]
x1[i]=(x1[i−1]+1)∗p[i],x2[i]=(x2[i−1]+x1[i−1]∗2+1)∗p[i]
而
f
[
i
]
=
f
[
i
−
1
]
+
(
3
∗
x
2
[
i
−
1
]
+
3
∗
x
1
[
i
−
1
]
+
1
)
∗
p
[
i
]
f[i]=f[i-1]+(3*x2[i-1]+3*x1[i-1]+1)*p[i]
f[i]=f[i−1]+(3∗x2[i−1]+3∗x1[i−1]+1)∗p[i]
而且这可以不用数组就能进行转移,于是实现效率O(N)
还有另外一种理解就是不要f[i],增加x3[i]为x^3,然后可以:
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
]
)
x3[i]=(x3[i-1]+3*x2[i-1]+3*x1[i-1]+1)*p[i]+x3[i-1]*(1-p[i])
x3[i]=(x3[i−1]+3∗x2[i−1]+3∗x1[i−1]+1)∗p[i]+x3[i−1]∗(1−p[i])
代码:
#include<bits/stdc++.h>
using namespace std;
#define re register
const int N=1e5+5;
int n;
double p,ans,x1,x2;
inline double rd(){
double re x=0,y=1.0;static char ch=0;ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
if(ch!='.')return x;ch=getchar();
while(isdigit(ch))x+=(y/=10)*(ch^48),ch=getchar();
return x;
}
signed main(){
// freopen("osu.in","r",stdin);
// freopen("osu.out","w",stdout);
scanf("%d",&n);
for(int re i=1;i<=n;i++)p=rd(),ans+=(3*x1+3*x2+1)*p,x2=(x2+2*x1+1)*p,x1=(x1+1)*p;
printf("%.1lf",ans);
return 0;
}