[ZJOI2019]开关

Description

有一个n位二进制数,一开始为0
每一轮中对于每一个i,有 p i ∑ p i p_i\over \sum p_i pipi的概率将这一位异或上1,每轮操作独立
问第一次变成目标状态的期望步数
n<=100,∑pi<=50000

Solution

考虑设F(x)表示在n步时变为目标状态的概率,显然有 F ( x ) = ∏ e p i x + ( − 1 ) t i e − p i x 2 F(x)=\prod{e^{p_ix}+(-1)^{t_i}e^{-p_ix}\over 2} F(x)=2epix+(1)tiepix这里的pi都是概率
这样不能保证是第一次,所以我们再设G(x)表示n步内变回0状态的概率,那么 G ( x ) = ∏ e p i x + e − p i x 2 G(x)=\prod{e^{p_ix}+e^{-p_ix}\over 2} G(x)=2epix+epix
设答案的EGF为H(x),其对应的OGF f ( x ) , g ( x ) , h ( x ) f(x),g(x),h(x) f(x),g(x),h(x),会满足 h ∗ g = f − &gt; h = f / g h*g=f -&gt;h=f/g hg=f>h=f/g
假如我们求出了答案的ogf h(x),那么问题的答案就是 h ′ ( 1 ) h&#x27;(1) h(1)
即我们对右边求导,将x=1代入
考虑知道EGF怎么求OGF,若 F ( x ) = ∑ a e v x F(x)=\sum ae^{vx} F(x)=aevx那么显然有 f ( x ) = ∑ a 1 − v x f(x)=\sum {a\over 1-vx} f(x)=1vxa
那么我们直接Dp求出EGF的表达式自然就知道了OGF的表达式
考虑 ( f ( x ) g ( x ) ) ′ = f ′ ( x ) g ( x ) − f ( x ) g ′ ( x ) g 2 ( x ) ({f(x)\over g(x)})&#x27;={f&#x27;(x)g(x)-f(x)g&#x27;(x)\over g^2(x)} (g(x)f(x))=g2(x)f(x)g(x)f(x)g(x),我们只需要知道 f ( 1 ) , f ′ ( 1 ) , g ( 1 ) , g ′ ( 1 ) f(1),f&#x27;(1),g(1),g&#x27;(1) f(1),f(1),g(1),g(1)就能算
但问题是 a 1 − v x a\over 1-vx 1vxa可能在1处未定义,怎么办呢?
我们可以直接通分,令 f ( x ) = A ( x ) B ( x ) , g ( x ) = C ( x ) D ( x ) f(x)={A(x)\over B(x)},g(x)={C(x)\over D(x)} f(x)=B(x)A(x),g(x)=D(x)C(x),注意到B(x)=D(x),所以我们等价于要算 ( A ( x ) C ( x ) ) ′ (A(x)\over C(x))&#x27; C(x))(A(x),也就是A(1),A’(1),C(1),C’(1),这些直接维护一个1-v的前缀积就好了
复杂度O(n∑pi),当然用NTT也可以做到O(∑pi log^2 ∑pi)

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;

typedef long long ll;

const int N=1e5+5,Mo=998244353;

int pwr(int x,int y) {
	int z=1;
	for(;y;y>>=1,x=(ll)x*x%Mo)
		if (y&1) z=(ll)z*x%Mo;
	return z;
}

int n,m,w,sum,f[N],g[N],t[N],p[N],pre[2][N],suf[2][N],v[N],A,C,dA,dC;

int main() {
	scanf("%d",&n);
	fo(i,1,n) scanf("%d",&t[i]);
	fo(i,1,n) scanf("%d",&p[i]),sum+=p[i];
	f[0]=g[0]=1;m=0;
	fo(i,1,n) {
		m+=p[i]<<=1;
		fd(j,m,p[i]) f[j]=(f[j-p[i]]+((t[i]&1)?-f[j]:f[j]))%Mo;
		fd(j,p[i]-1,0) f[j]=(t[i]&1)?-f[j]:f[j];
		fd(j,m,p[i]) g[j]=(g[j-p[i]]+g[j])%Mo;
	}
	fo(i,0,m) 
		if (!(i&1)) {
			v[i/2]=(ll)(i-m/2)*pwr(sum,Mo-2)%Mo;
			f[i/2]=f[i];g[i/2]=g[i];
		}
	m/=2;
	pre[0][0]=1-v[0];pre[1][0]=-v[0];
	fo(i,1,m) {
		pre[0][i]=(ll)pre[0][i-1]*(1-v[i])%Mo;
		pre[1][i]=(ll)pre[1][i-1]*(1-v[i])%Mo;
		(pre[1][i]-=(ll)pre[0][i-1]*v[i]%Mo)%=Mo;
	}
	suf[0][m]=1-v[m];suf[1][m]=-v[m];
	fd(i,m-1,0) {
		suf[0][i]=(ll)suf[0][i+1]*(1-v[i])%Mo;
		suf[1][i]=(ll)suf[1][i+1]*(1-v[i])%Mo;
		(suf[1][i]-=(ll)suf[0][i+1]*v[i]%Mo)%=Mo;
	}
	fo(i,0,m) {
		int now=(ll)(i?pre[0][i-1]:1)*(i<m?suf[0][i+1]:1)%Mo;
		(A+=(ll)f[i]*now%Mo)%=Mo;(C+=(ll)g[i]*now%Mo)%=Mo;
		now=(ll)(i?pre[0][i-1]:1)*(i<m?suf[1][i+1]:0)%Mo;
		(now+=(ll)(i?pre[1][i-1]:0)*(i<m?suf[0][i+1]:1)%Mo)%=Mo;
		(dA+=(ll)f[i]*now%Mo)%=Mo;(dC+=(ll)g[i]*now%Mo)%=Mo;
	}
	int ans=((ll)dA*C%Mo-(ll)A*dC%Mo)%Mo;
	ans=(ll)ans*pwr(pwr(C,2),Mo-2)%Mo;
	printf("%d\n",(ans+Mo)%Mo);
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
zjoi2019是指第八届浙江省信息学奥林匹克竞赛(Zhejiang Olympiad in Informatics, zjoi),是浙江省级的信息学竞赛活动。这项竞赛旨在发掘和培养浙江省优秀的信息学人才,提高学生在计算机科学和算法设计等方面的能力。zjoi2019分为两个阶段,分别是省赛和决赛。 省赛是选拔赛阶段,所有报名参赛的学生都可以参加。在省赛中,学生将进行一系列的算法编程测试,测试他们在解决实际问题过程中的编程能力、算法设计思维和团队合作能力。省赛中表现优秀的选手将有机会晋级到决赛。 决赛是省选的最终阶段,在决赛中,选手将经历更加复杂和挑战性的编程测试。他们将面对更高难度的算法问题和实际应用问题,需要发挥出自己的创造力和思维能力,迅速解决问题。决赛中表现出色的选手将有机会代表浙江省参加全国性的信息学奥林匹克竞赛。 通过参加zjoi2019浙江省选,学生们将接触到高水平的算法竞赛,提升自己的编程和算法设计能力。同时,他们还能与其他对信息学感兴趣的同学们进行交流和学习,拓宽自己的视野,培养团队合作和竞赛意识。此外,脱颖而出的选手还有机会获得奖项和奖学金等荣誉,为自己的学术和职业道路打下坚实的基础。 总之,zjoi2019浙江省选是对浙江省信息学人才的全面选拔和培养,为学生们提供了一个展示自己技能和才华的舞台。这对于提高学生们的算法设计和编程能力、培养他们的团队合作精神和创新能力具有重要意义。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值