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

                
            
        
浙公网安备 33010602011771号