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

第二类斯特林数

定义

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

求法

递推:

\(S(n,m)=S(n-1,m-1)+m\cdot S(n-1,m)\)

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

容斥:

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

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

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

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

性质

\[n^k=\sum_{i=0}^nS(k,i)\times i!\times 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\n",ans);
    return 0;
}
posted @ 2019-01-21 19:41  YoungNeal  阅读(421)  评论(0编辑  收藏  举报