zoukankan      html  css  js  c++  java
  • Luogu P5824 十二重计数法(小球盒子计数)

    Link

    假如有(n)个球,要放进(m)个盒子,求方案数。

    ( ext{I}):球之间互不相同,盒子之间互不相同。

    显然答案为(m^n)

    ( ext{II}):球之间互不相同,盒子之间互不相同,每个盒子至多装一个球。

    依次把球放进盒子,放第(i)个球时有(m-i+1)种方案,因此答案为(m^{underline n})

    ( ext{III}):球之间互不相同,盒子之间互不相同,每个盒子至少装一个球。

    相当于把(n)个数划分为(m)个有序集合,因此答案为(left{natop m ight}m!)

    ( ext{IV}):球之间互不相同,盒子全部相同。

    枚举有多少个盒子放了球,然后方案数就是将(n)个数划分为若干个无序集合,因此答案为(sumlimits_{i=1}^mleft{natop i ight})

    ( ext{V}):球之间互不相同,盒子全部相同,每个盒子至多装一个球。

    显然答案为([nle m])

    ( ext{VI}):球之间互不相同,盒子全部相同,每个盒子至少装一个球。

    显然答案为(left{natop m ight})

    ( ext{VII}):球全部相同,盒子之间互不相同。

    每个盒子装任意个球都只有一种方案,OGF为(frac1{1-x}),因此答案为([x^n]frac1{(1-x)^m}={n+m-1choose n})

    ( ext{VIII}):球全部相同,盒子之间互不相同,每个盒子至多装一个球。

    显然答案为({mchoose n})

    ( ext{IX}):球全部相同,盒子之间互不相同,每个盒子至少装一个球。

    此时每个盒子装球的OGF为(frac x{1-x}),因此答案为([x^n]frac{x^m}{(1-x)^m}={n-1choose m-1})

    ( ext{X}):球全部相同,盒子全部相同。

    相当于将(n)划分为(m)个无序自然数的和,答案为(p(n+m,m)=[x^n]prodlimits_{i=1}^mfrac1{1-x^i})

    ( ext{XI}):球全部相同,盒子全部相同,每个盒子至多装一个球。

    显然答案为([nle m])

    ( ext{XII}):球全部相同,盒子全部相同,每个盒子至少装一个球。

    相当于将(n)划分为(m)个无序正整数的和,答案为(p(n,m)=[x^{n-m}]prodlimits_{i=1}^mfrac1{1-x^i})

    #include<cstdio>
    #include<cstring>
    #include<numeric>
    #include<algorithm>
    const int N=524289,P=998244353;
    int n,m,deg,len,fac[N],inv[N],ifac[N],rev[N],w[N],S[N],p[N];
    int inc(int a,int b){return a+=b-P,a+=a>>31&P;}
    int dec(int a,int b){return a-=b,a+=a>>31&P;}
    int mul(int a,int b){return 1ll*a*b%P;}
    int pow(int a,int k){int r=1;for(;k;k>>=1,a=mul(a,a))if(k&1)r=mul(a,r);return r;}
    int C(int n,int m){return m<0||m>n? 0:mul(mul(fac[n],ifac[m]),ifac[n-m]);}
    int getlen(int n){return 1<<(32-__builtin_clz(n));}
    void init(int n)
    {
        int lim=1<<(len=32-__builtin_clz(n)),g=pow(3,(P-1)/lim);
        w[lim>>1]=1,fac[0]=ifac[0]=inv[0]=fac[1]=ifac[1]=inv[1]=1;
        for(int i=1;i<lim;++i) rev[i]=(rev[i>>1]>>1)|(i&1? lim>>1:0);
        for(int i=(lim>>1)+1;i<lim;++i) w[i]=mul(w[i-1],g);
        for(int i=(lim>>1)-1;i;--i) w[i]=w[i<<1];
        for(int i=2;i<=lim;++i) fac[i]=mul(fac[i-1],i),ifac[i]=mul(ifac[i-1],inv[i]=mul(inv[P%i],P-P/i));
    }
    void NTT(int*a,int lim,int f)
    {
        if(!~f) std::reverse(a+1,a+lim);
        for(int i=0,x=len-__builtin_ctz(lim);i<lim;++i) if(i<rev[i]>>x) std::swap(a[i],a[rev[i]>>x]);
        for(int i=1;i<lim;i<<=1) for(int j=0,d=i<<1;j<lim;j+=d) for(int k=0,x;k<i;++k) x=mul(a[i+j+k],w[i+k]),a[i+j+k]=dec(a[j+k],x),a[j+k]=inc(a[j+k],x);
        if(!~f) for(int i=0,x=P-(P-1)/lim;i<lim;++i) a[i]=mul(a[i],x);
    }
    void Inv(int*a,int*b,int deg)
    {
        if(deg==1) return b[0]=pow(a[0],P-2),void();
        static int t[N];int lim=getlen(deg*2-2);
        Inv(a,b,(deg+1)>>1),memcpy(t,a,deg<<2),memset(t+deg,0,(lim-deg)<<2);
        NTT(t,lim,1),NTT(b,lim,1);
        for(int i=0;i<lim;++i) b[i]=mul(dec(2,mul(b[i],t[i])),b[i]);
        NTT(b,lim,-1),memset(b+deg,0,(lim-deg)<<2);
    }
    void Der(int*a,int*b,int deg){for(int i=1;i<deg;++i)b[i-1]=mul(a[i],i);b[deg-1]=0;}
    void Int(int*a,int*b,int deg){for(int i=1;i<deg;++i)b[i]=mul(a[i-1],inv[i]);b[0]=0;}
    void Ln(int*a,int*b,int deg)
    {
        static int t[N];int lim=getlen(deg*2-2);
        Inv(a,t,deg),Der(a,b,deg),NTT(t,lim,1),NTT(b,lim,1);
        for(int i=0;i<lim;++i) t[i]=mul(t[i],b[i]);
        NTT(t,lim,-1),Int(t,b,deg),memset(t,0,lim<<2),memset(b+deg,0,(lim-deg)<<2);
    }
    void Exp(int*a,int*b,int deg)
    {
        if(deg==1) return b[0]=1,void();
        static int t[N];int lim=getlen(deg*2-2);
        Exp(a,b,(deg+1)>>1),Ln(b,t,deg);
        for(int i=0;i<deg;++i) t[i]=dec(a[i],t[i]);
        memset(t+deg,0,(lim-deg)<<2),++t[0],NTT(t,lim,1),NTT(b,lim,1);
        for(int i=0;i<lim;++i) b[i]=mul(b[i],t[i]);
        NTT(b,lim,-1),memset(b+deg,0,(lim-deg)<<2),memset(t+deg,0,(lim-deg)<<2);
    }
    void calcS()
    {
        static int F[N],G[N],lim=1<<len,deg=std::min(n,m)+1;
        for(int i=0;i<deg;++i) F[i]=mul(pow(i,n),ifac[i]),G[i]=i&1? P-ifac[i]:ifac[i];
        NTT(F,lim,1),NTT(G,lim,1);
        for(int i=0;i<lim;++i) S[i]=mul(F[i],G[i]);
        NTT(S,lim,-1),memset(S+deg,0,(lim-deg)*4);
    }
    void calcp()
    {
        static int F[N];
        for(int i=1;i<=m;++i) for(int j=i;j<=n;j+=i) F[j]=inc(F[j],inv[j/i]);
        Exp(F,p,n+1);
    }
    int main()
    {
        scanf("%d%d
    ",&n,&m);
        init(2*std::max(n,m)),calcS(),calcp();
        printf("%d
    ",pow(m,n));
        printf("%d
    ",mul(C(m,n),fac[n]));
        printf("%d
    ",mul(S[m],fac[m]));
        printf("%d
    ",std::accumulate(S+1,S+m+1,0,inc));
        printf("%d
    ",n<=m);
        printf("%d
    ",S[m]);
        printf("%d
    ",C(m+n-1,n));
        printf("%d
    ",C(m,n));
        printf("%d
    ",C(n-1,m-1));
        printf("%d
    ",p[n]);
        printf("%d
    ",n<=m);
        printf("%d
    ",n<m? 0:p[n-m]);
    }
    
  • 相关阅读:
    Android:日常学习笔记(7)———探究UI开发(1)
    Android:日常学习笔记(6)——探究活动(4)
    JavaScript:基础扩展(1)——JSON
    JavaScript:学习笔记(3)——正则表达式的应用
    正则表达式:快速入门
    LeetCode_Easy_471:Number Complement
    Java实现——字符串分割以及复制目录下的所有文件
    DOM、SAX、JDOM、DOM4J以及PULL在XML文件解析中的工作原理以及优缺点对比
    一个简单电商网站开发过程中的业务资料整理
    大道至简,不简则死
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12659575.html
Copyright © 2011-2022 走看看