第一类斯特林数
意义:将n个不同的元素划分成m个环的方案数。
递推式:
(通常第一类斯特林数用小写 $s$ 表示,而第二类斯特林数用大写 $S$ 表示)
$$
s(n,m)=s(n-1,m-1)+s(n-1,m) imes (n-1)
$$
关于定义:
$P_{n}^{k} $ 表示从n个为物品中选出k个排列的方案数,显然有:
$$
C_{n}^{k}=frac{P_{n}^{k}}{k!}
$$
$$
P_{n}^{k}=n imes (n-1) imes (n-2) imes...... imes (n-k+1)
$$
考虑把式子展开,
对于第 $i$ 项(即 $n^{i}$ 项)的系数表示成有 $i$ 项选择 $n$ ,剩余的 $k-i$ 项选择 $k$ 个常数,所以对于第 $i$ 项系数是选择的 $i$ 个常数的乘积的和。
我们考虑把斯特林数左右反过来,因为每一行数的个数都差 $1$ ,这里的定义是向左看齐。
$$
s_{t}(n,m)=s_{t}(n-1,m-1) imes (n-1)+s_{t}(i-1,j)
$$
这样就这个递推式就可以理解为前 $i$ 个数我选了 $m$ 个数的乘积的和,因为可以选择的常数其实是从 $0$ ~ $k-1$ ,所以乘的系数是 $(n-1)$ 。
所以呢
$$
P_{n}^{k}=s(k,k) imes n^{k}-s(k,k-1) imes n^{k-1}...
$$
$$
P_{n}^{k}=sum _{i=0}^{k}(-1)^{k-i} imes s(k,i) imes n^{i}
$$
所以第一类斯特林数是排列数公式的展开系数。
同时也得到第一类有符号斯特林数的多项式形式
$$
n(n-1)(n-2)...(n-k+1)=sum_{i=0}^{k}(-1)^{k-i}S(k,i)n^{i}
$$
也可以推出第一类无符号斯特林数的多项式形式
$$
n(n+1)(n+2)...(n+k-1)=sum_{i=0}^{k}S(k,i)n^{i}
$$
当前得到的式子,左边用分治 $NTT$ 求出第 $i$ 项系数即为 $S(k,i)$ ,这个求法效率是 $O(nlog^{2}n)$
接下来 $O(nlogn)$ 的倍增做法,
考虑当我们已经知道 $S_{n}$ 的生成函数为
$$
prod_{i=0}^{n-1}(x+i)=sum f_{i}x^{i}
$$
以此来研究 $S_{2n}$ 的生成函数
$$
prod_{i=n}^{2n-1}(x+i)\
=prod_{i=0}^{n-1}(x+i+n)\
=sum_{i=0}^{n}f_{i}(x+n)^{i}
$$
再用二项式定理展开:
$$
=sum_{i=0}^{n}f_{i}sum C_{i}^{j}x^{j}n^{i-j}\
=sum_{j=0}^{n}sum_{i=j}^{n}f_{i}frac{i!}{j!(i-j)!}x^{j}n^{i}n^{-j}\
=sum_{j=0}^{n}frac{1}{j!n^{j}}(sum_{i-j}^{n}frac{i!}{(i-j)!}n^{i})x^{j}
$$
那么对于括号内的多项式 $NTT$ $O(nlogn)$ 得到,对于奇数的情况先求出 $2n$ 的答案,再单独乘最后一项。
以下代码:
#include<bits/stdc++.h> #define il inline #define LL long long #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=3e5+5,p=998244353; int t1[N],t2[N],t3[N],t4[N]; int n,a,b,jc[N],ny[N],t=1,l,f[N],v[N],g[2][40]; il int read(){ int x,f=1;char ch; _(!)ch=='-'?f=-1:f;x=ch^48; _()x=(x<<1)+(x<<3)+(ch^48); return f*x; } il int ksm(LL a,int y){ LL b=1; while(y){ if(y&1)b=b*a%p; a=a*a%p;y>>=1; } return b; } il int mu(int x,int y){ return (x+y>=p)?x+y-p:x+y; } il int C(int n,int m){ return 1ll*jc[n]*ny[m]%p*ny[n-m]%p; } il void init(int n){ t=1;l=0; while(t<=n)t<<=1,l++; for(int i=0;i<t;i++)v[i]=(v[i>>1]>>1)|((i&1)<<l-1); } il void dft(int *x,int op){ for(int i=0;i<t;i++)if(i<v[i])swap(x[i],x[v[i]]); for(int i=1,z=1;i<t;i<<=1,z++){ int wn=g[op][z]; for(int j=0;j<t;j+=i<<1){ for(int w=1,A,B,k=0;k<i;k++,w=1ll*w*wn%p){ A=x[j+k],B=1ll*x[i+j+k]*w%p; x[j+k]=mu(A,B);x[i+j+k]=mu(A,p-B); } } } int kk=ksm(t,p-2); if(op)for(int i=0;i<t;i++)x[i]=1ll*x[i]*kk%p; } il void solve(int *x,int n){ if(n==1){ x[0]=0;x[1]=1; return; } if(n&1){ solve(x,n-1);x[n]=0; for(int i=n-1;i>=0;i--)x[i+1]=mu(1ll*(n-1)*x[i+1]%p,x[i]); return; } solve(x,n>>1); init(n); for(int i=(n>>1)+1;i<=n;i++) t1[i]=t2[i]=t3[i]=t4[i]=0; for(int i=0;i<=(n>>1);i++){ t1[i]=1ll*x[i]*ksm(n>>1,i)%p*jc[i]%p; t2[i]=ny[i]; } reverse(t1,t1+(n>>1)+1); dft(t1,0);dft(t2,0); for(int i=0;i<t;i++)t3[i]=1ll*t1[i]*t2[i]%p; dft(t3,1);reverse(t3,t3+(n>>1)+1); for(int i=0;i<=(n>>1);i++)t4[i]=1ll*t3[i]*ksm(ksm(n>>1,i),p-2)%p*ny[i]%p; dft(t4,0);dft(x,0); for(int i=0;i<t;i++)x[i]=1ll*x[i]*t4[i]%p; dft(x,1); } int main() { n=read();a=read();b=read(); if(n==1&&a==1&&b==1)return puts("1"),0; if(a+b-1>n||a<1||b<1)return puts("0"),0; g[0][0]=3;g[1][0]=ksm(3,p-2); while(t<=n)t<<=1,l++; for(int i=1,z=1;i<t;i<<=1,z++){ g[0][z]=ksm(g[0][0],(p-1)/(i<<1)); g[1][z]=ksm(g[1][0],(p-1)/(i<<1)); } jc[0]=1;for(int i=1;i<=t;i++)jc[i]=1ll*i*jc[i-1]%p; ny[t]=ksm(jc[t],p-2);for(int i=t;i;i--)ny[i-1]=1ll*i*ny[i]%p; solve(f,n-1); printf("%d ",1ll*f[a+b-2]*C(a+b-2,a-1)%p); return 0; }
一些关于第一类斯特林数的性质:
1. $s(0,0)=1$
2. $s(n,0)=0 (n>0)$
3. $s(n,1)=(n-1)!$
4. $s(n,n-1)=C_{n}^{2}$
5. $s(n,2)=(n-1)! imes sum_{i=1}^{n-1} frac{i}{1}$
6. $s(n,n-2)=2 imes C_{n}^{3}+3 imes C_{n}^{4}$
7. $sum_{k=0}^{n}s(n,k)=n!$
第二类斯特林数
意义:将 $n$ 个不同的元素拆成 $m$ 个集合的方案数(不存在空集)。
(与第一类不同于,第二类球在集合中无序的)
递推式:
$$
S(n,m)=S(n-1,m-1)+m imes S(n-1,m)
$$
容斥式子:
枚举空盒子的个数,求出至少有 $i$ 个空盒的方案数容斥得到恰好有 $m$ 个盒子的方案数。
$$
S(n,m)=frac{1}{m!}sum_{k=0}^{m}(-1)^{k} imes C_{m}^{k} imes (m-k)^{n}
$$
$ps:$ 因为集合是相同的,所以最后要 $ imes frac{1}{m!}$
观察到式子是卷积的形式,所以可以 $NTT$ 在 $O(nlogn)$ 内求出 $S(n,0),S(n,1)......$
性质:
$$
n^{k}=sum_{i=0}^{k}S(k,i) imes i! imes C_{n}^{i}
$$
左边相当于把 $k$ 个球随便放在 $i$ 个不同的盒子里
右边表示枚举 $k$ 个球装在 $i$ 个盒子里,(因为左边盒子是不同的,为了一致 $ imes i!$ 表示不同的盒子),再组合数 $C_{n}^{k}$ 选出 $k$ 个非空盒子。
继续变化
$$
n^{k}=sum_{i=0}^{k}S(k,i)n^{underline{k}}
$$
$n^{underline{k}}$ 表示 $n$ 的 $k$ 次下降幂,等于 $n imes (n-1) imes (n-2) imes ...... imes (n-k+1)$
斯特林反演后续填坑...