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;
}
静渊以有谋,疏通而知事。