zoukankan      html  css  js  c++  java
  • [CTSC2019]珍珠 题解

    [CTSC2019]珍珠 题解

    Problem

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

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

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

    Solution

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

    那么,题目的要求就是:

    [sumlimits_{i=1}^D lfloor frac{A_i}{2} floor ge m ]

    即:

    [2m leq 2sumlimits_{i=1}^D lfloor frac{A_i}{2} floor =sumlimits_{i=1}^D A_i -sumlimits_{i=1}^D (A_i pmod 2) = n- sumlimits_{i=1}^D (A_i pmod 2) ]

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

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

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

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

    展开得:

    [egin{align} f_i &=inom{D}{i}frac{n!}{2^i}[x^n](e^x-e^{-x})^i(e^x)^{D-i} \ &=inom{D}{i}frac{n!}{2^i}[x^n](sumlimits_{k=0}^i inom{i}{k}e^{xk} (-e^{-x})^{i-k} )e^{D-i} \ &=inom{D}{i}frac{n!}{2^i}[x^n]sumlimits_{k=0}^i inom{i}{k}(-1)^{i-k} e^{(D+2k-2i)x} \ &=inom{D}{i}frac{1}{2^i}sumlimits_{k=0}^i inom{i}{k}(-1)^{i-k} (D+2k-2i)^n \ &=inom{D}{i}frac{i!}{2^i}sumlimits_{k=0}^i frac{(-1)^{i-k}(D+(i-k))^n}{(i-k)!} imes k! end{align} ]

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

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

    [f_k=sumlimits_{i=k}^D inom{i}{k} g_i ]

    二项式反演得:

    [egin{align} g_k &=sumlimits_{i=k}^D (-1)^{i-k} inom{i}{k} f_i \ &=frac{1}{k!}sumlimits_{i=k}^D frac{(-1)^{i-k}}{(i-k)!} imes 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
    ");
            return 0;
        }
    
        if(n-2*m>=D){
            printf("%d
    ",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
    ",Ans);
    
        return 0;
    }
    
  • 相关阅读:
    word2vec原理(一) CBOW与Skip-Gram模型基础
    条件随机场CRF(三) 模型学习与维特比算法解码
    条件随机场CRF(二) 前向后向算法评估标记序列概率
    linux下如何强制卸载设备?
    docker build时如何使用代理?
    如何配置docker使用代理?
    linux下tar解压时报"gzip: stdin: unexpected end of file"如何处理?
    ubuntu下如何安装valgrind?
    linux下如何睡眠1ms?
    linux用户空间如何控制gpio?
  • 原文地址:https://www.cnblogs.com/zjy123456/p/13864249.html
Copyright © 2011-2022 走看看