LG4705 玩游戏

玩游戏

Alice 和 Bob 又在玩游戏。 对于一次游戏,首先 Alice 获得一个长度为 \(n\) 的序列 \(a\),Bob 获得一个长度为 \(m\) 的序列 \(b\)。之后他们各从自己的序列里随机取出一个数,分别设为 \(a_x, b_y\),定义这次游戏的 \(k\) 次价值为 \((a_x + b_y)^k\)。 由于他们发现这个游戏实在是太无聊了,所以想让你帮忙计算对于 \(i = 1, 2, \cdots, t\),一次游戏 \(i\) 次价值的期望是多少。 由于答案可能很大,只需要求出模 \(998244353\) 下的结果即可。

\(1 \leq n, m \leq 10^5,1 \leq t \leq 10^5\)

题解

https://www.luogu.com.cn/blog/user48173/solution-p4705

一次游戏的期望 \(k\) 次价值为

\[ans_k=\frac{1}{nm}\sum_{i=1}^n\sum_{j=1}^m(a_i+b_j)^k\\ nm\cdot ans=\sum_{i=1}^n\sum_{j=1}^m\sum_{r=0}^k\binom{k}{r}a_i^rb_j^{k-r}\\ =k!\sum_{r=0}^k\frac{\sum_{i=1}^na_i^r}{r!}\frac{\sum_{j=1}^mb_j^{k-r}}{(k-r)!} \]

显然问题转化成了求等指数幂和。

\[\sum_{i=1}^n\frac{1}{1-a_ix}=\frac{\sum_{i=1}^n\prod_{j\neq i}(1-a_jx)}{\prod_{i=1}^n(1-a_ix)} \]

分母可以分治NTT求。分子的 \([x^i]\) 等于分母的 \([x^i]\times (n-i)\)

时间复杂度 \(O(n\log^2 n+t\log t)\)

CO int N=262144;
int omg[2][N],rev[N];
int fac[N],inv[N],ifac[N];

void NTT(poly&a,int dir){
	int lim=a.size(),len=log2(lim);
	for(int i=0;i<lim;++i) rev[i]=rev[i>>1]>>1|(i&1)<<(len-1);
	for(int i=0;i<lim;++i)if(i<rev[i]) swap(a[i],a[rev[i]]);
	for(int i=1;i<lim;i<<=1)
		for(int j=0;j<lim;j+=i<<1)for(int k=0;k<i;++k){
			int t=mul(omg[dir][N/(i<<1)*k],a[j+i+k]);
			a[j+i+k]=add(a[j+k],mod-t),a[j+k]=add(a[j+k],t);
		}
	if(dir==1){
		int ilim=fpow(lim,mod-2);
		for(int i=0;i<lim;++i) a[i]=mul(a[i],ilim);
	}
}
poly operator~(poly a){
	int n=a.size();
	poly b={fpow(a[0],mod-2)};
	if(n==1) return b;
	a.resize(1<<(int)ceil(log2(n)));
	for(int lim=2;lim<2*n;lim<<=1){
		poly c(a.begin(),a.begin()+lim);
		c.resize(lim<<1),NTT(c,0);
		b.resize(lim<<1),NTT(b,0);
		for(int i=0;i<lim<<1;++i) b[i]=mul(2+mod-mul(c[i],b[i]),b[i]);
		NTT(b,1),b.resize(lim);
	}
	return b.resize(n),b;
}
poly operator*(poly a,poly b){
	int n=a.size()+b.size()-1;
	int lim=1<<(int)ceil(log2(n));
	a.resize(lim),NTT(a,0);
	b.resize(lim),NTT(b,0);
	for(int i=0;i<lim;++i) a[i]=mul(a[i],b[i]);
	NTT(a,1),a.resize(n);
	return a;
}

int a[N],b[N];

poly solve(int a[],int l,int r){
	if(l==r) return poly{1,mod-a[l]};
	int mid=(l+r)>>1;
	return solve(a,l,mid)*solve(a,mid+1,r);
}
int main(){
	omg[0][0]=1,omg[0][1]=fpow(3,(mod-1)/N);
	omg[1][0]=1,omg[1][1]=fpow(omg[0][1],mod-2);
	fac[0]=fac[1]=1;
	inv[0]=inv[1]=1;
	ifac[0]=ifac[1]=1;
	for(int i=2;i<N;++i){
		omg[0][i]=mul(omg[0][i-1],omg[0][1]);
		omg[1][i]=mul(omg[1][i-1],omg[1][1]);
		fac[i]=mul(fac[i-1],i);
		inv[i]=mul(mod-mod/i,inv[mod%i]);
		ifac[i]=mul(ifac[i-1],inv[i]);
	}
	int n=read<int>(),m=read<int>();
	for(int i=1;i<=n;++i) read(a[i]);
	for(int i=1;i<=m;++i) read(b[i]);
	int t=read<int>();
	poly da=solve(a,1,n),ua(n);
	poly db=solve(b,1,m),ub(m);
	for(int i=0;i<n;++i) ua[i]=mul(da[i],n-i);
	for(int i=0;i<m;++i) ub[i]=mul(db[i],m-i);
	da.resize(t+1),db.resize(t+1);
	ua=ua*~da,ua.resize(t+1);
	ub=ub*~db,ub.resize(t+1);
	for(int i=0;i<=t;++i){
		ua[i]=mul(ua[i],ifac[i]);
		ub[i]=mul(ub[i],ifac[i]);
	}
	ua=ua*ub,ua.resize(t+1);
	int inm=fpow(mul(n,m),mod-2);
	for(int i=1;i<=t;++i){
		int ans=mul(ua[i],mul(fac[i],inm));
		printf("%d\n",ans);
	}
	return 0;
}

posted on 2020-01-13 16:08  autoint  阅读(144)  评论(0编辑  收藏  举报

导航