Description
给定 \(n\) 求第二列斯特林数的第 \(n\) 行
Solution
首先定义第二类斯特林数 \(S(n,m)\) 为将 \(n\) 个球放到 \(m\) 个盒子里的方案数
然后容易由 \(dp\) 得到一个递推式
\[S(n,m)=S(n-1,m-1)+m\times S(n-1,m) \]
但是这是 \(O(n^2)\) 的,一般是不能拿来做题的
所以我们考虑一个容斥的做法
\[S(n,m)=\frac 1 {m!}\sum _ {k=0}^m (-1)^k \times \binom m k \times (m-k)^n \]
后面是容斥,枚举空盒子的数量,然后剩下的随便放
因为是随便放,所以要容斥
因为每个盒子是一样的,所以还要除以 \(m!\)
这题给到这里就能做了
把式子推一下
\[S(n,m)=\sum_{k=0}^m \frac {(-1)^k}{k!}\times \frac{(m-k)^n} {(m-k)!} \]
这里是个卷积,预处理阶乘,逆元就做完了
第二类斯特林数的一个性质:
\[n^k=\sum_{i=0}^k S(k,i)\times i! \times \binom n i \]
直接上组合意义,左边是在 \(n\) 个互不相同盒子里面放 \(k\) 个小球的方案
右边是枚举盒子的数量,放在哪几个盒子里面,然后因为盒子不一样,然后就在来个阶乘就没了
至于组合推导……link
博主会了就不推了
斯特林反演啥的留坑
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm{
inline int read()
{
int res=0,f=1; char k;
while(!isdigit(k=getchar())) if(k=='-') f=-1;
while(isdigit(k)) res=res*10+k-'0',k=getchar();
return res*f;
}
const int N=8e5+10,mod=167772161,g=3;
int n,r[N],fac[N],inv[N],m,A[N],B[N];
inline int ksm(int x,int y)
{
int res=1; for(;y;y>>=1,x=x*x%mod) if(y&1) res=res*x%mod;
return res;
}
inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int del(int x,int y){return x-y<0?x-y+mod:x-y;}
inline void NTT(int *f,int n,int opt)
{
for(int i=0;i<n;++i) r[i]=r[i>>1]>>1|((i&1)?(n>>1):0);
for(int i=0;i<n;++i) if(i<r[i]) swap(f[i],f[r[i]]);
for(int p=2;p<=n;p<<=1)
{
int len=p>>1,tmp=ksm(g,(mod-1)/p);
if(opt==-1) tmp=ksm(tmp,mod-2);
for(int k=0;k<n;k+=p)
{
int buf=1;
for(int l=k;l<k+len;++l)
{
int tt=buf*f[l+len]%mod;
f[l+len]=del(f[l],tt);
f[l]=add(f[l],tt);
buf=buf*tmp%mod;
}
}
}
int t=ksm(n,mod-2);
if(opt==-1) for(int i=0;i<n;++i) f[i]=f[i]*t%mod;
return ;
}
signed main()
{
n=read()+1; fac[0]=fac[1]=1; inv[0]=inv[1]=1;
for(int i=2;i<=n;++i) fac[i]=fac[i-1]*i%mod;
for(int i=2;i<=n;++i) inv[i]=mod-mod/i*inv[mod%i]%mod;
for(int i=1;i<=n;++i) inv[i]=inv[i]*inv[i-1]%mod;
for(int i=0;i<n;++i)
{
int res;
if(i&1) res=mod-1; else res=1;
A[i]=res*inv[i]%mod;
B[i]=ksm(i,n-1)*inv[i]%mod;
}
for(m=n+n,n=1;n<=m;n<<=1);
NTT(A,n,1); NTT(B,n,1);
for(int i=0;i<n;++i) A[i]=A[i]*B[i]%mod;
NTT(A,n,-1);
for(int i=0;i<(m>>1);++i) printf("%lld ",A[i]);
return 0;
}
}
signed main(){return yspm::main();}