「学习笔记」第二类斯特林数入门

Description

link

给定 \(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();}

猜你喜欢

转载自www.cnblogs.com/yspm/p/13382022.html