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;
}

猜你喜欢

转载自www.cnblogs.com/autoint/p/12187793.html