有一个数列(a),满足(a_0=0),(forall i>0)满足(a_i)有(frac{p_i}{100})的概率为(a_{i-1}+1),有(1-frac{p_i}{100})的概率为(0)
求((sumlimits_{i=1}^n a_i)^2)的期望
数据范围:(1leq n leq 2*10^6,0leq p_i leq 100)
Solution
其实真的是一道不能再小清新的概d。。。
和时机成熟之时不同,直接考虑转移的时候的变化好像并不是很方便。。(实际上也可以做但是要维护四五六七八个量就很烦还容易错==),因为并不是连续的而是一段一段的
比较简单的做法是直接看最后的形式:((sumlimits_{i=1}^n a_i)^2=sumlimits_{i=1}^n a_i^2+2sumlimits_{i=1}^n a_isumlimits_{j=1}^{i-1}a_j)
所以我们求(E( a_i^2))和(E(a_isumlimits_{j=1}^{i-1}a_j))就好了
具体的话(f_i)表示(E(a_i)),(g_i)表示(E(a_i^2)),(h_i)表示(E(a_isumlimits_{j=1}^{i-1}a_j)),那么有(为了方便直接用(p_i)表示除以(100)之后的结果了):
[egin{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})sumlimits_{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
",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();
}