题意:给出长度为n待填的01串,第i位填1概率为p[i],整个串中每一段极长的,连续为1长度为m的串对答案有的贡献(极长表示如果"1111"贡献了64,那么它的子串将不再贡献,比如"11"不再做出8的贡献),求答案的期望
题解:
定义:f[i]表示第i位的连续为1后缀的长度的期望,h[i]表示第i位的连续为1的长度平方的期望(平方的期望不一定等于期望的平方,所以不能直接用f[i]平方来搞)。
每一位填0/1都是独立的(互不影响),假设第i-1位的连续为1后缀长度为x,考虑第i位,如果填0那么显然这一位对答案没有贡献,如果填1(如果填0那么贡献为0直接不管),那么这一位(注意只看这一位)对答案的贡献为。根据定义,
的值应该为f[i-1],
的值应该为g[i-1]。所以这一位的贡献为
现在再考虑如何求 和
这两个数组。
比较容易得到:
现在考虑 :第i-1位的连续为1的长度平方的期望为g[i-1],第i-1位的连续为1的长度的期望为f[i-1],假设第i-1位的连续为1后缀长度为x,考虑第i位(如果填0那么贡献为0直接不管),如果填1那么这一位连续为1后缀的长度平方为
。根据定义,
的值应该为f[i-1],
的值应该为g[i-1]。所以,
之前做BZOJ时乱写的辣鸡题解,成功地骗过了当时的自己......
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+4;
int n;
double pr[N];
double f[N],g[N];
double ans;
int main() {
scanf("%d",&n);
for (register int i=1;i<=n;++i)
scanf("%lf",&pr[i]);
for (register int i=1;i<=n;++i) {
f[i]=pr[i]*(f[i-1]+1);
g[i]=pr[i]*(g[i-1]+2*f[i-1]+1);
ans+=pr[i]*(3*g[i-1]+3*f[i-1]+1);
}
printf("%.1lf\n",ans);
return 0;
}