LOJ#3045. 「ZJOI2019」开关

传送门

什么神仙题……

这里是生成函数的做法,似乎还有\(FWT\)的做法 这里

\(P=\sum p_i\)

对于第\(i\)个位置,考虑它在\(n\)次之后合法的概率,设其指数生成函数为\(F_i(x)\)

\[\begin{aligned} F_i(x) &=\sum_{j\bmod 2=s_i}\left(p_i\over P\right)^j{x^j\over j!}\\ &={e^{p_ix\over P}+(-1)^{s_i}e^{-p_ix\over P}\over 2}\\ \end{aligned} \]

所以总的概率的\(EGF\)

\[\begin{aligned} F(x)=\prod_{i=1}^n {e^{p_ix\over P}+(-1)^{s_i}e^{-p_ix\over P}\over 2} \end{aligned} \]

然而这里有可能在走完\(n\)步之前就到达了终止状态,这种情况可以认为是第一次到达终止状态后,走了若干个环又回到了终止状态

我们考虑走了\(n\)步回到出发点的概率

\[\begin{aligned} G(x)=\prod_{i=1}^n {e^{p_ix\over P}+e^{-p_ix\over P}\over 2} \end{aligned} \]

\(H(x)\)表示答案的生成函数,令这三个函数的\(OGF\)分别为\(f,g,h\),有

\[\begin{aligned} h(x)g(x)=f(x)\\ h(x)={f(x)\over g(x)} \end{aligned} \]

由于\(h(x)\)是概率生成函数,所以答案就是\(h'(1)\)

由于

\[\begin{aligned} h'(x)={f'(x)g(x)-g'(x)f(x)\over g^2(x)} \end{aligned} \]

我们把\(F(x)\)写成如下形式

\[\begin{aligned} F(x)=\sum_{i=-P}^P a_ie^{ix\over P} \end{aligned} \]

那么对应的\(f(x)\)就是

\[\begin{aligned} f(x)=\sum_{i=-P}^P a_i{1\over 1-{ix\over P}} \end{aligned} \]

然而我们发现当\(x=1\)\(f(x)\)\(g(x)\)不收敛(当\(i=P\)时后面分数形如\({1\over 0}\)),所以我们需要把\(f(x)\)\(g(x)\)同时乘上\(\prod_{i=1}^n \left(1-{ix\over P}\right)\),这样并不影响答案。此时\(f(x)\)

\[\begin{aligned} f(x)=\sum_{i=-P}^P a_i\prod_{j\neq i}\left({1-{jx\over P}}\right) \end{aligned} \]

\(x=1\)时,后面\(j=P\)可以导致后面为\(0\),所以有

\[\begin{aligned} f(1)=a_P\prod_{j\neq P}\left({1-{jx\over P}}\right) \end{aligned} \]

而对于\(f'(x)\),由于有

\[\begin{aligned} \left(\prod_i (1+a_ix)\right)'=\sum_i a_i\prod_{j\neq i} (1+a_jx) \end{aligned} \]

我们把\(f'(x)\)分成两部分计算,一部分是\(i\neq P\)的,有

\[\begin{aligned} A(x)=\sum_{i\neq P}a_i\sum_{k\neq i}\left(-k\over P\right)\prod_{j\neq i,j\neq k}\left(1-{jx\over P}\right) \end{aligned} \]

而当\(x=1\)\(k\neq P\)时,后面是\(0\),所以

\[\begin{aligned} A(1)=-\sum_{i\neq P}a_i\prod_{j\neq i,j\neq P}\left(1-{j\over P}\right) \end{aligned} \]

而后面\(i=P\)的部分,有

\[\begin{aligned} B(1)=a_P\sum_{i\neq P}\left(-{i\over P}\right)\prod_{j\neq i,j\neq P}\left(1-{j\over P}\right) \end{aligned} \]

所以

\[\begin{aligned} f'(1) &=A(1)+B(1)\\ &=-\prod_{i\neq P}\left(1-\frac{i}{P}\right)\left(\sum_{j\neq P}\frac{a_j}{1-\frac{j}{P}}+a_P\sum_{j\neq P}\frac{\frac{j}{P}}{1-\frac{j}{P}}\right) \end{aligned} \]

\(g'(x)\)也类似,可以直接代入了

据说还可以继续化简,然而后面我真的看不懂了

//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int P=998244353,inv2=(P+1)>>1;
inline void upd(R int &x,R int y){(x+=y)>=P?x-=P:0;}
inline int inc(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
	R int res=1;
	for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
	return res;
}
const int N=5e4+5;
int f[N<<1],g[N<<1],tmp[N<<1],s[N],p[N],n,res,sum;
inline int calc(int *f){
	R int res=1,ism=ksm(sum,P-2);
	fp(i,-sum,sum-1){
		R int iv=mul(inc(i,P),ism);
		res=mul(res,P+1-iv);
	}
	return mul(res,f[sum+N]);
}
inline int dir(int *f){
	R int res=1,ret=0,ism=ksm(sum,P-2);
	fp(i,-sum,sum-1){
		R int iv=mul(inc(i,P),ism);
		res=mul(res,P+1-iv);
		upd(ret,mul(ksm(P+1-iv,P-2),inc(f[i+N],mul(f[sum+N],iv))));
	}
	return inc(0,P-mul(res,ret));
}
int main(){
//	freopen("testdata.in","r",stdin);
	scanf("%d",&n);
	fp(i,1,n)scanf("%d",&s[i]);
	fp(i,1,n)scanf("%d",&p[i]);
	f[N]=g[N]=1;
	fp(i,1,n){
		R int v=p[i];
		sum+=v;
		fp(j,-sum,sum)tmp[j+N]=0;
		R int c1=inv2,c2=s[i]?P-inv2:inv2;
		fp(j,-sum+v,sum)upd(tmp[j+N],mul(c1,f[j+N-v]));
		fd(j,sum-v,-sum)upd(tmp[j+N],mul(c2,f[j+N+v]));
		fp(j,-sum,sum)f[j+N]=tmp[j+N],tmp[j+N]=0;
		fp(j,-sum+v,sum)upd(tmp[j+N],mul(c1,g[j+N-v]));
		fd(j,sum-v,-sum)upd(tmp[j+N],mul(c1,g[j+N+v]));
		fp(j,-sum,sum)g[j+N]=tmp[j+N];
	}
	R int res=calc(g);
	res=ksm(res,P-2),res=mul(res,res);
	res=mul(res,inc(mul(dir(f),calc(g)),P-mul(dir(g),calc(f))));
	printf("%d\n",res);
	return 0;
}
posted @ 2019-12-17 19:01  源曲明  阅读(170)  评论(0编辑  收藏  举报