[CTSC2019]珍珠 题解

[CTSC2019]珍珠 题解

Problem

\(n\)个在范围\([1,D]\)内的整数均匀随机变量

求至少能选出\(m\)个瓶子,使得存在一种方案,选择一些变量,并把选出来的每一个变量放到一个瓶子中,满足每个瓶子都恰好装两个值相同的变量的概率

请输出概率乘上\(D^n\)后对998244353取模的值

Solution

考虑到\(n\)的范围是\(10^9\),我们可以换一个方向枚举,考虑枚举每个权值出现的次数,设其为\(A_i\)

那么,题目的要求就是:

\[\sum\limits_{i=1}^D \lfloor \frac{A_i}{2} \rfloor \ge m \]

即:

\[2m \leq 2\sum\limits_{i=1}^D \lfloor \frac{A_i}{2} \rfloor =\sum\limits_{i=1}^D A_i -\sum\limits_{i=1}^D (A_i \pmod 2) = n- \sum\limits_{i=1}^D (A_i \pmod 2) \]

现在问题变成,出现次数为奇数的颜色数小于等于\(2m-n\)

我们设\(g_i\)为恰好有\(i\)个奇数的方案数,则答案就是\(\sum\limits_{i=0}^{2m-n}g_i\)

恰好不好求,我们考虑转化成至少,设\(f_i\)为至少\(i\)个奇数的方案数,有:

\[f_i=\binom{D}{i}n![x^n](\frac{e^x-e^{-x}}{2})^i(e^x)^{D-i} \]

展开得:

\[\begin{align} f_i &=\binom{D}{i}\frac{n!}{2^i}[x^n](e^x-e^{-x})^i(e^x)^{D-i} \\ &=\binom{D}{i}\frac{n!}{2^i}[x^n](\sum\limits_{k=0}^i \binom{i}{k}e^{xk} (-e^{-x})^{i-k} )e^{D-i} \\ &=\binom{D}{i}\frac{n!}{2^i}[x^n]\sum\limits_{k=0}^i \binom{i}{k}(-1)^{i-k} e^{(D+2k-2i)x} \\ &=\binom{D}{i}\frac{1}{2^i}\sum\limits_{k=0}^i \binom{i}{k}(-1)^{i-k} (D+2k-2i)^n \\ &=\binom{D}{i}\frac{i!}{2^i}\sum\limits_{k=0}^i \frac{(-1)^{i-k}(D+(i-k))^n}{(i-k)!} \times k! \end{align} \]

化成这样以后卷积的形式就已经很明显了

再考虑\(f_i\)\(g_i\)的关系,由于:

\[f_k=\sum\limits_{i=k}^D \binom{i}{k} g_i \]

二项式反演得:

\[\begin{align} g_k &=\sum\limits_{i=k}^D (-1)^{i-k} \binom{i}{k} f_i \\ &=\frac{1}{k!}\sum\limits_{i=k}^D \frac{(-1)^{i-k}}{(i-k)!} \times f_ii! \end{align} \]

也可以卷积

Code

#include<bits/stdc++.h>
#define PR 3
#define mod 998244353
#define LL  long long
using namespace std;

LL Ans;
int n,m,D;
int rev[400005];
LL inv[400005],fact[400005],invf[400005];
LL f[400005],g[400005],F[400005],G[400005];

inline LL read(){
    LL x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){
       if(ch=='-')f=-1;
       ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
       x=(x<<1)+(x<<3)+ch-'0';
       ch=getchar();
    }
    return x*f;
}

inline LL quick_power(LL x,int k){
    LL res=1;
    while(k){
        if(k&1) 
            res=res*x%mod;
        x=x*x%mod;k>>=1;
    }
    return res;
}

void Initialize(){
    inv[1]=1;
    fact[0]=invf[0]=1;
    fact[1]=invf[1]=1;
    for(register int i=2;i<=D;++i){
        inv[i]=(mod-mod/i)*inv[mod%i]%mod;
        invf[i]=invf[i-1]*inv[i]%mod;
        fact[i]=fact[i-1]*i%mod;
    }
    return;
}

void NTT(LL *F,int Lim,int op){
    for(register int i=0;i<Lim;++i){
        if(i<rev[i])
            swap(F[i],F[rev[i]]);
    }
    for(register int mid=1;mid<Lim;mid<<=1){
        int R=mid<<1;
        LL rt=quick_power(PR,(mod-1)/R);
        for(register int j=0;j<Lim;j+=R){
            LL w=1;
            for(register int k=0;k<mid;++k){
                LL x=F[j|k],y=w*F[j|k|mid]%mod;
                F[j|k|mid]=(x-y+mod)%mod;
                F[j|k]=(x+y)%mod;
                w=w*rt%mod;
            }
        }
    }
    if(op==-1){
        reverse(F+1,F+Lim);
        LL Inv=quick_power(Lim,mod-2);
        for(register int i=0;i<Lim;++i)
            F[i]=F[i]*Inv%mod;
    }
    return;
}

int main(){
    
    int Lim,Len;

    D=read();n=read();m=read();

    if(n<2*m){
        printf("0\n");
        return 0;
    }

    if(n-2*m>=D){
        printf("%d\n",quick_power(D,n));
        return 0;
    }

    Initialize();

    for(register int i=0;i<=D;++i)
        f[i]=((i&1?-1:+1)*invf[i]*quick_power((D-2*i+mod)%mod,n)%mod+mod)%mod;

    for(register int i=0;i<=D;++i)
        g[i]=invf[i];

    Lim=1,Len=-1;
    while(Lim<(D+1<<1))   
        Lim<<=1,++Len;
    for(register int i=0;i<Lim;++i)
        rev[i]=(rev[i>>1]>>1)|((i&1)<<Len);
    NTT(f,Lim,+1);NTT(g,Lim,+1);
    for(register int i=0;i<Lim;++i)
        f[i]=f[i]*g[i]%mod;
    NTT(f,Lim,-1);
    
    for(register int i=0;i<=D;++i)
        G[i]=f[i]*fact[i]%mod*fact[D]%mod*invf[D-i]%mod*quick_power(inv[2],i)%mod;

    for(register int i=0;i<=D;++i)
        F[i]=(((D-i)&1?-1:+1)*invf[D-i]+mod)%mod;

    Lim=1,Len=-1;
    while(Lim<(D+1<<1))   
        Lim<<=1,++Len;
    for(register int i=0;i<Lim;++i)
        rev[i]=(rev[i>>1]>>1)|((i&1)<<Len);
    NTT(F,Lim,+1);NTT(G,Lim,+1);
    for(register int i=0;i<Lim;++i)
        F[i]=F[i]*G[i]%mod;
    NTT(F,Lim,-1);
    
    for(register int i=0;i<=n-2*m;++i)
        Ans=(Ans+F[D+i]*invf[i]%mod)%mod;
    
    printf("%lld\n",Ans);

    return 0;
}
posted @ 2020-10-23 15:08  zjy123456  阅读(126)  评论(0编辑  收藏  举报