序列

### Description

  有一个数列\(a\),满足\(a_0=0\)\(\forall i>0\)满足\(a_i\)\(\frac{p_i}{100}\)的概率为\(a_{i-1}+1\),有\(1-\frac{p_i}{100}\)的概率为\(0\)

  求\((\sum\limits_{i=1}^n a_i)^2\)的期望

​   

  数据范围:\(1\leq n \leq 2*10^6,0\leq p_i \leq 100\)

  

Solution

  其实真的是一道不能再小清新的概d。。。

​  和时机成熟之时不同,直接考虑转移的时候的变化好像并不是很方便。。(实际上也可以做但是要维护四五六七八个量就很烦还容易错==),因为并不是连续的而是一段一段的

  比较简单的做法是直接看最后的形式:\((\sum\limits_{i=1}^n a_i)^2=\sum\limits_{i=1}^n a_i^2+2\sum\limits_{i=1}^n a_i\sum\limits_{j=1}^{i-1}a_j\)

  所以我们求\(E( a_i^2)\)\(E(a_i\sum\limits_{j=1}^{i-1}a_j)\)就好了

​  具体的话\(f_i\)表示\(E(a_i)\)\(g_i\)表示\(E(a_i^2)\)\(h_i\)表示\(E(a_i\sum\limits_{j=1}^{i-1}a_j)\),那么有(为了方便直接用\(p_i\)表示除以\(100\)之后的结果了):

\[\begin{aligned} f_i&=p_i*(f_{i-1}+1)+(1-p_i)*0\\ g_i&=p_i*(g_{i-1}+2f_{i-1}+1)+(1-p_i)*0\\ h_i&=p_i*(h_{i-1}+(g_{i-1}+f_{i-1})\sum\limits_{j=1}^{i-2}f_j)+(1-p_i)*0\\ \end{aligned} \]

  然后就做完了

  

Code

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=2e6+10,MOD=998244353;
int f[N],g[N],h[N],sum[N];
int p[N];
int n,ans;
int mul(int x,int y){return 1LL*x*y%MOD;}
int plu(int x,int y){return (1LL*x+y)%MOD;}
int mns(int x,int y){return (1LL*x+MOD-y)%MOD;}
int sqr(int x){return 1LL*x*x%MOD;}
int ksm(int x,int y){
    int ret=1,base=x;
    for (;y;y>>=1,base=mul(base,base))
        if (y&1) ret=mul(ret,base);
    return ret;
}
void dp(){
    f[0]=0; sum[0]=0;
    for (int i=1;i<=n;++i){
        f[i]=mul(p[i],f[i-1]+1);
        g[i]=mul(p[i],plu(g[i-1],plu(mul(2,f[i-1]),1)));
        h[i]=plu(h[i-1],plu(i>=2?sum[i-2]:0,plu(g[i-1],f[i-1])));
        h[i]=mul(p[i],h[i]);
        sum[i]=plu(sum[i-1],f[i]);
    }
    ans=0;
    for (int i=1;i<=n;++i){
        ans=plu(ans,g[i]);
        ans=plu(ans,2LL*h[i]);
    }
    printf("%d\n",ans);
}
 
int main(){
#ifndef ONLINE_JUDGE
    freopen("a.in","r",stdin);
#endif
    int x,inv;
    inv=ksm(100,MOD-2);
    scanf("%d",&n);
    for (int i=1;i<=n;++i){
        scanf("%d",&x);
        p[i]=mul(inv,x);
    }
    dp();
}
posted @ 2019-03-23 09:48  yoyoball  阅读(198)  评论(0编辑  收藏