LOJ3045 ZJOI2019 开关
题意
九条可怜是一个贪玩的女孩子。
这天,她和她的好朋友法海哥哥去玩密室逃脱。在他们面前的是 \(n\) 个开关,开始每个开关都是关闭的状态。要通过这关,必须要让开关达到指定的状态。目标状态由一个长度为 \(n\) 的 \(01\) 数组 \(s\) 给出,\(s_i = 0\) 表示第 \(i\) 个开关在最后需要是关着的,\(s_i = 1\) 表示第 \(i\) 个开关在最后需要被打开。
然而作为闯关者,可怜和法海并不知道 \(s\)。因此他们决定采用一个比较稳妥的方法:瞎按。他们根据开关的外形、位置,通过一些玄学的方法给每一个开关赋予了一个值 \(p_i(p_i > 0)\)。每一次,他们会以正比于 \(p_i\) 的概率(第 \(i\) 个开关被选中的概率是 \(\frac{p_i}{\sum_{j=1}^n p_j}\))选择并按下一个开关。开关被按下后,状态会被反转,即开变关,关变开。注意,每一轮的选择都是ᅠ完全独立的。
在按开关的过程中,一旦当前开关的状态达到了 \(s\),那么可怜和法海面前的门就会打开,他们会马上停止按开关的过程并前往下一关。作为一名欧皇,可怜在按了 \(\sum_{i=1}^n s_i\) 次后,就打开了大门。为了感受一下自己的运气是多么的好,可怜想要让你帮她计算一下,用这种随机按的方式,期望需要按多少次开关才能通过这一关。
题解
考虑生成函数
\(F(x)\) 表示按 \(i\) 次开关到达目标状态的概率的 EGF, \(G(x)\) 表示按 \(i\) 次开关回到原来状态的概率的 EFG, \(f(x)\) 是 \(F(x)\) 的 OGF, \(g(x)\) 是 \(G(x)\) 的OGF
设 \(P=\sum_{i=1}^np_i\), 显然
\[ F(x)=\frac1{2^n}\Pi_{i=1}^n\left(e^{\frac{p_i}Px}+(-1)^{s_i}e^{-\frac{p_i}Px}\right) \]
这玩意儿的意义就是如果 \(s_i=0\) 那么这个位置要按奇数步否则要按偶数步
\[ G(x)=\frac1{2^n}\Pi_{i=1}^n\left(e^{\frac{p_i}Px}+e^{-\frac{p_i}Px}\right) \]
然后设答案的概率的 OGF 为 \(h(x)\), 易得 \(h(x)g(x)=f(x)\), 即 \(h(x)=\frac {f(x)}{g(x)}\)
换一种方式表示 \(F(x)\)
\[ F(x)=\sum_{i=-P}^Pa_ie^{\frac iPx}=\sum_{i=-P}^Pa_i\sum_{j=0}^\infty\frac{\left(\frac{ix}p\right)^j}{j!} \]
所以
\[ f(x)=\sum_{i=-P}^Pa_i\sum_{j=0}^\infty\left(\frac{ix}p\right)^j=\sum_{i=-P}^P\frac{a_i}{1-\frac{ix}p} \]
因为 \(F(x)\) 转 \(f(x)\) 第 \([x^i]\) 项要乘以 \(i!\)
然后答案就是 \(h'(1)=\left(\frac{f(1)}{g(1)}\right)'=\frac{f'(1)g(1)-g'(1)f(1)}{g^2(1)}\)
但是我们发现把 \(x=1\) 代入 \(f(x)\) 和 \(g(x)\) 函数求得值趋于无穷
所以把 \(f(x)\) 和 \(g(x)\) 同时乘上 \(\Pi_{i=-P}^P(1+\frac iPx)\)
于是新记的
\[ f(x)=\sum_{i=-P}^Pa_i\Pi_{j=-P,j\neq i}^P\left(1+\frac jPx\right) \]
于是
\[ f'(x)=\sum_{i=-P}^Pa_i\Pi_{j=-P,j\neq i}^P\frac jP\Pi_{k=-P,k\neq i,j}^P\left(1+\frac kPx\right) \]
这个式子看上去很难算,但是我们发现第一个式子只在 \(i=-P\) 有值,第二式子只在 \(i=-P\) 或 \(j=-P\) 有值,直接暴力代入即可
#include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
template<typename T>inline void rd(T&x){int fl=0,ch;while(ch=getchar(),ch<48||57<ch)fl^=!(ch^45);x=(ch&15);while(ch=getchar(),47<ch&&ch<58)x=x*10+(ch&15);if(fl)x=-x;}
template<typename T>inline void pt(T x){if(x<0)putchar('-'),x=-x;if(x>9)pt(x/10);putchar(x%10+48);}
template<typename T>inline void pt(T x,int ch){pt(x),putchar(ch);}
template<typename T>inline T max(const T&x,const T&y){return x<y?y:x;}
template<typename T>inline T min(const T&x,const T&y){return x<y?x:y;}
const int N=105,S=50005,P=998244353,I2=1;
int fpow(int a,int b){
int res=1;for(;b;b>>=1,a=1ll*a*a%P)if(b&1)res=1ll*res*a%P;return res;
}
int n,p,invp,fz,fm,s[N],poolf[S<<1],poolg[S<<1],poolh[S<<1],*f=poolf+S,*g=poolg+S,*h=poolh+S;
int fun(int*f){
int res=1;
for(int i=-p+1;i<=p;++i)res=1ll*res*(1+1ll*i*invp%P)%P;
return 1ll*res*f[-p]%P;
}
int dao(int*f){
int res=0,sum=1;
for(int i=-p+1;i<=p;++i)sum=1ll*sum*(1+1ll*i*invp%P)%P;
for(int i=-p+1;i<=p;++i){
int tmp=1ll*sum*fpow(1+1ll*i*invp%P,P-2)%P;
(res+=1ll*f[-p]*i%P*invp%P*tmp%P)%=P;
(res+=-1ll*f[i]*tmp%P)%=P;
}
return res;
}
signed main(){
rd(n);rep(i,1,n)rd(s[i]);
f[0]=g[0]=1;
rep(i,1,n){
int x;rd(x);
rep(j,-p,p)(h[j+x]+=1ll*f[j]*I2%P)%=P,(h[j-x]+=1ll*(s[i]?P-1ll:1ll)*f[j]%P*I2%P)%=P;
memcpy(poolf,poolh,sizeof(poolf));
memset(poolh,0,sizeof(poolh));
rep(j,-p,p)(h[j+x]+=1ll*g[j]*I2%P)%=P,(h[j-x]+=1ll*g[j]*I2%P)%=P;
memcpy(poolg,poolh,sizeof(poolg));
memset(poolh,0,sizeof(poolh));
p+=x;
}
std::reverse(f-p,f+p+1);
std::reverse(g-p,g+p+1);
invp=fpow(p,P-2);
fz=1ll*dao(f)*fun(g)%P-1ll*dao(g)*fun(f)%P;
fm=fun(g),fm=1ll*fm*fm%P;
pt((1ll*fz*fpow(fm,P-2)%P+P)%P,'\n');
return 0;
}