题解 P1654 【OSU!】
ShineEternal
2019-08-17 18:40:34
节选自[vercont的洛谷日报](https://www.luogu.org/problemnew/solution/P1654)
## 题目链接:
https://www.luogu.org/problemnew/solution/P1654
## 分析:
我们可以观察到每次对答案的贡献是三次方级别的。
吼啊,我不会三次方期望啊。
仔细观察,首先发现一次方的期望是很好弄的。
于是设$a[i]$表示前i位中第i位为1的长度的期望:
则有
$$a[i]=(a[i-1]+1)\times p[i]$$
$tag$:即为在i-1的末尾加一个概率为$p[i]$出现的1
接着推平方
设$b[i]$表示前i位中第i位为1的长度的平方的期望:
则有
$$b[i]=(b[i-1]+2\times a[i-1]+1)\times p[i]$$
$tag$:期望的线性延伸:
$$x^2->(x+1)^2->x^2+2x+1$$
运用这种方法,我们可以在求出$a[i]$的基础上推出$b[i]$
同理,设$f[i]$表示前i位中第i位为1的长度的立方的期望:
则有:
$$f[i]=(f[i-1]+3\times b[i-1]+3\times a[i-1]+1)\times p[i]$$
- 哇塞我要A紫题了!!!
然后在满心欢喜的提交上去后发现wa了。
![](https://i.loli.net/2019/08/13/nr152QKgxqmH3Xv.jpg)
显然,我们还有没考虑到的地方?
是什么呢?
是最后求得的答案与中间过渡式子的不同性。
其实,前三个式子我们都只考虑**第i位**,这样做是为了递推下面的式子,但是答案让我们求出最终的期望分数,也就是**前n位**,这时输出f[n]自然就炸了。
所以,只需把三次方递推式稍微变形一下即可;
$$f[i]=(f[i-1]+3\times b[i-1]+3\times a[i-1]+1)\times p[i]+f[i-1]\times (1-p[i])=f[i-1]+(3\times b[i-1]+3\times a[i-1]+1)\times p[i]$$
这样最终的$f[n]$就是答案喽!
### code:
```cpp
//AC记录:https://www.luogu.org/record/21569138
#include<cstdio>
using namespace std;
double a[100005],b[100005],f[100005],p[100005];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lf",&p[i]);
a[i]=(a[i-1]+1)*p[i];
b[i]=(b[i-1]+2*a[i-1]+1)*p[i];
f[i]=f[i-1]+(3*b[i-1]+3*a[i-1]+1)*p[i];
}
printf("%.1lf\n",f[n]);
return 0;
}
```
~~学好数学期望,递推AC紫题!(其实这应该算dp~~
![](https://i.loli.net/2019/08/13/Ba9VxM6gkp3CvqQ.jpg)
$tag:$这题还可以扩展到k次,也就是$X^k$,用二项式定理$O(nk^2)$解决
觉得不够快?食用NTT对其加速可以达到$O(nklog_k)$