• [总结] 第二类斯特林数学习笔记


    第二类斯特林数

    定义

    第二类斯特林数 (S(n,m)) 表示把 (n)不同的小球放进 (m) 个相同的盒子里的方案数。

    求法

    递推:

    (S(n,m)=S(n-1,m-1)+mcdot S(n-1,m))

    讨论最后一个球是否单独成盒。

    容斥:

    [S(n,m)=frac 1{m!}sum_{k=0}^m (-1)^kcdot C(m,k)cdot(m-k)^n ]

    枚举空盒的个数,剩下的随便放,盒子是相同的最后要除以 (m!)

    化简一下就是 $$S(n,m)=sum_{k=0}^m(-1)^kcdot frac{(m-k)^n}{(m-k)!k!}$$

    这式子是个卷积,所以可以在 (O(nlog n)) 的时间内求出 (S(n,0),S(n,1)dots)

    性质

    [n^k=sum_{i=0}^nS(k,i) imes i! imes C(n,i) ]

    左边是 (k) 个球随意放在 (n) 个盒子里方案数

    右边是枚举有球的盒子个数 (i),那就是把 (k) 个球放进 (i) 个盒子的方案数(盒子不同所以乘上 (i!)),里面再乘上 (n) 个盒子选 (i) 个的方案数。

    例题

    [HEOI2016] 求和

    傻逼题,把斯特林数展开就没了。

    #include<bits/stdc++.h>
    using std::min;
    using std::max;
    using std::swap;
    using std::vector;
    typedef double db;
    typedef long long ll;
    #define pb(A) push_back(A)
    #define inv(x) ksm(x,mod-2)
    #define pii std::pair<int,int>
    #define all(A) A.begin(),A.end()
    #define mp(A,B) std::make_pair(A,B)
    const int N=4e5+5;
    const int mod=998244353;
    
    int n,lim;
    int fac[N],ifac[N];
    int rev[N],a[N],b[N];
    
    int ksm(int a,int b,int ans=1){
        while(b){
            if(b&1) ans=1ll*ans*a%mod;
            a=1ll*a*a%mod;b>>=1;
        } return ans;
    }
    
    void ntt(int *f,int opt){
        for(int i=0;i<lim;i++) if(i<rev[i]) swap(f[i],f[rev[i]]);
        for(int mid=1;mid<lim;mid<<=1){
            int tmp=ksm(3,(mod-1)/(mid<<1));
            if(opt<0) tmp=inv(tmp);
            for(int R=mid<<1,j=0;j<lim;j+=R){
                int w=1;
                for(int k=0;k<mid;k++,w=1ll*w*tmp%mod){
                    int x=f[j+k],y=1ll*w*f[j+k+mid]%mod;
                    f[j+k]=(x+y)%mod,f[j+k+mid]=(mod+x-y)%mod;
                }
            }
        } if(opt<0){
            for(int in=inv(lim),i=0;i<lim;i++) f[i]=1ll*f[i]*in%mod;
        }
    }
    
    int getint(){
        int X=0,w=0;char ch=getchar();
        while(!isdigit(ch))w|=ch=='-',ch=getchar();
        while( isdigit(ch))X=X*10+ch-48,ch=getchar();
        if(w) return -X;return X;
    }
    
    signed main(){
        n=getint();
        lim=1;while(lim<=n+n) lim<<=1;
        for(int i=1;i<lim;i++) rev[i]=(rev[i>>1]>>1)|(i&1?lim>>1:0);
        fac[0]=ifac[0]=1;
        for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%mod;
        ifac[n]=inv(fac[n]);
        for(int i=n-1;i;i--) ifac[i]=1ll*ifac[i+1]*(i+1)%mod;
        for(int i=0;i<=n;i++){
            a[i]=(1ll*ifac[i]*(i&1?mod-1:1)%mod+mod)%mod;
            b[i]=(1ll*(ksm(i,n+1)-1+mod)%mod*inv(i-1)%mod*ifac[i]%mod+mod)%mod;
        }  b[1]=n+1;
        ntt(a,1),ntt(b,1);
        for(int i=0;i<lim;i++) a[i]=1ll*a[i]*b[i]%mod;
        ntt(a,-1);ll now=1,ans=0;
        for(int i=0;i<=n;i++){
            a[i]=1ll*a[i]*fac[i]%mod*now%mod;
            (ans+=a[i])%=mod;
            now=now*2%mod;
        } printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    类型检查-类型表达式:类型系统是一种逻辑系统
    计算机程序是建立在计算机硬件和一系列规则、协议、规范、算法基础之上的;
    类型的基石:数据类型、函数类型
    类型安全
    类型检查-类型系统
    动态类型-类型绑定
    类型安全与类型检查是什么?
    怎样写一个新编程语言
    同名的cookie会不会存在多个
    php array_map与array_walk使用对比
  • 原文地址:https://www.cnblogs.com/YoungNeal/p/10300599.html
Copyright © 2020-2023  润新知