玩游戏
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}^nsum_{j=1}^m(a_i+b_j)^k\
nmcdot ans=sum_{i=1}^nsum_{j=1}^msum_{r=0}^kinom{k}{r}a_i^rb_j^{k-r}\
=k!sum_{r=0}^kfrac{sum_{i=1}^na_i^r}{r!}frac{sum_{j=1}^mb_j^{k-r}}{(k-r)!}
]
显然问题转化成了求等指数幂和。
[sum_{i=1}^nfrac{1}{1-a_ix}=frac{sum_{i=1}^nprod_{j
eq i}(1-a_jx)}{prod_{i=1}^n(1-a_ix)}
]
分母可以分治NTT求。分子的 ([x^i]) 等于分母的 ([x^i] imes (n-i))。
时间复杂度 (O(nlog^2 n+tlog 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
",ans);
}
return 0;
}