[笔记] 斯特林数
第一类斯特林数
\(\begin{bmatrix}n\\ k \end{bmatrix}\) 表示\(n\) 个有区别的元素划分成\(k\) 个环的方案数。
\(\begin{bmatrix}n\\ 1 \end{bmatrix}=(n-1)!\) 此时的每种轮换对应\(n\) 个循环同构的排列。
\(\begin{bmatrix}n\\ n \end{bmatrix} = 1\ ,\begin{bmatrix}n\\ n-1 \end{bmatrix} = {n \choose 2}\) 因为当每个轮换都是单元素或双元素时,轮换与子集是等价的。
\(\begin{bmatrix}n\\ k \end{bmatrix}=(n-1)\begin{bmatrix}n-1\\ k \end{bmatrix}+\begin{bmatrix}n-1\\ k-1 \end{bmatrix},n\geq1\)
\(n! = \sum\limits_{k=0}^n \begin{bmatrix}n\\ k \end{bmatrix}\) 轮换与排列是一一对应的(其实一个排列类似一个置换)。
\(x^{\overline n}=\sum\limits_{k} \begin{bmatrix}n\\ k \end{bmatrix} x^k\ ,n\geq 0\)
\(x^{\underline n}= \sum\limits_{k} \begin{bmatrix}n\\ k \end{bmatrix} (-1)^{n-k} x^k\ ,n\geq 0\)
求解
求解\(\begin{bmatrix}n\\ k \end{bmatrix}\)
由于\(x^{\overline n}=\sum\limits_{k=0}^n\begin{bmatrix}n\\ k\end{bmatrix} x^k\) ,所以我们可以直接通过分治FFT求\(x^{\overline n}\) 在\(\mathcal{O}(n\log^2n)\) 求出。
优化:
当我们求完\(x^{\overline n}\) 后,如果可以直接求出\((x+n)^{\overline n}\) ,那么可以直接得出\(x^{\overline{2n}}\) ,时间复杂度则降为\(T(n)=T(\frac{n}{2})+\mathcal{O}(n\log n)=\mathcal{O}(n\log n)\) 。
设\(x^{\overline n}=\sum\limits_{k=0}^n a_ix^i\) ,
则
\(\begin{aligned}(x+n)^{\overline n}&=\sum_{i=0}^n a_i(x+n)^i\\&=\sum_{i=0}^n a^i \sum_{j=0}^i {i \choose j}x^j n^{i-j} \\&=\sum_{i=0}^n x^i \sum_{j=i}^n {j \choose i} a^j n^{j-i}\\&=\sum_{i=0}^n\frac{x^i}{i!}\sum_{j=i}^n\frac{n^{j-i}}{(j-i)!}\ j!a_j \end{aligned}\)
后面的部分是一个减法卷积,我们可以反转其中一个变成加法卷积即可。
#include<iostream>
#include<cstdio>
#define R register int
using namespace std;
namespace Luitaryi {
const int N=530000,G=3,Gi=55924054,M=167772161;
inline int qpow(int a,int b) { R ret=1;
for(;b;b>>=1,a=1ll*a*a%M) if(b&1) ret=1ll*ret*a%M; return ret;
}
int n,K,len,p[N],fac[N],ifac[N];
inline void init(int n) {
K=1,len=0; while(K<=n) K<<=1,++len;
for(R i=1;i<K;++i) p[i]=(p[i>>1]>>1)|((i&1)<<(len-1));
}
inline void ntt(int* a,int op) {
for(R i=1;i<K;++i) if(i<p[i]) swap(a[i],a[p[i]]);
for(R l=1;l<K;l<<=1) {
R w1=qpow(~op?G:Gi,(M-1)/(l<<1)),wn,x,y;
for(R len=l<<1,i=0;i<K;i+=len) { wn=1;
for(R j=0;j<l;++j,wn=1ll*w1*wn%M)
x=a[i+j],y=1ll*a[i+j+l]*wn%M,a[i+j]=(x+y)%M,a[i+j+l]=(x-y+M)%M;
}
} if(~op) return ; R Inv=qpow(K,M-2);
for(R i=0;i<K;++i) a[i]=1ll*a[i]*Inv%M;
}
int f[N],a[N],b[N],ta[N],tb[N];
inline void calc(const int* f,int n,int* h) {
init(n<<1);
for(R i=0;i<=n;++i) ta[n-i]=1ll*f[i]*fac[i]%M;
for(R t=1,i=0;i<=n;++i,t=1ll*t*n%M)
tb[i]=1ll*ifac[i]*t%M;
for(R i=n+1;i<K;++i) ta[i]=tb[i]=0;
ntt(ta,1),ntt(tb,1);
for(R i=0;i<K;++i) ta[i]=1ll*ta[i]*tb[i]%M;
ntt(ta,-1);
for(R i=0;i<=n;++i) h[i]=1ll*ta[n-i]*ifac[i]%M;
}
inline void solve(int n,int* f) {
if(n==0) return ;
R md=n>>1;
solve(md,f);
calc(f,md,a);
init(n);
for(R i=0;i<=md;++i) b[i]=f[i];
for(R i=md+1;i<K;++i) a[i]=b[i]=0;
ntt(a,1),ntt(b,1);
for(R i=0;i<K;++i) a[i]=1ll*a[i]*b[i]%M;
ntt(a,-1);
if(n&1) for(R i=0;i<=n;++i)
f[i]=((i?a[i-1]:0)+1ll*(n-1)*a[i])%M;
else for(R i=0;i<=n;++i) f[i]=a[i];
}
inline void main() {
scanf("%d",&n);
f[0]=fac[0]=fac[1]=ifac[0]=ifac[1]=1;
for(R i=2;i<=n;++i) fac[i]=1ll*fac[i-1]*i%M;
ifac[n]=qpow(fac[n],M-2);
for(R i=n-1;i>=2;--i) ifac[i]=1ll*ifac[i+1]*(i+1)%M;
solve(n,f);
for(R i=0;i<=n;++i)
printf("%d ",f[i]);
}
} signed main() {Luitaryi::main(); return 0;}
第二类斯特林数
\(\begin{Bmatrix}n\\ k \end{Bmatrix}\) 表示\(n\) 个有区别的元素划分成\(k\) 个非空子集的方案数。
\(\begin{Bmatrix}0\\ 0 \end{Bmatrix}=1\)
\(\begin{Bmatrix}n\\ 0 \end{Bmatrix}=0\ ,n\geq 1\)
\(\begin{Bmatrix}n\\ 1 \end{Bmatrix}=1\ ,n\geq 1\)
\(\begin{Bmatrix}n\\ 2 \end{Bmatrix}=2^{n-1}-1\ ,n\geq 1\) 强制至少一个元素在集合\(A\) ,剩下\(2^{n-1}\) 种方案,减去集合\(B\) 是空集的方案。
\(\begin{Bmatrix}n\\ 0 \end{Bmatrix}=0\ ,n\geq 1\)
\(\begin{Bmatrix}n\\ k \end{Bmatrix}=k\begin{Bmatrix}n-1\\ k \end{Bmatrix}+\begin{Bmatrix}n-1\\ k-1 \end{Bmatrix}\ ,n\geq 1\)
\(\begin{Bmatrix}n\\ n \end{Bmatrix} = 1\ ,\begin{Bmatrix}n\\ n-1 \end{Bmatrix} = {n \choose 2}\)
性质
\(x^{n}=\sum\limits_{k} \begin{Bmatrix}n\\ k \end{Bmatrix} x^{\underline k}\ ,n\geq 0\)
\(x^{n}= \sum\limits_{k} \begin{Bmatrix}n\\ k \end{Bmatrix} (-1)^{n-k} x^{\overline k}\ ,n\geq 0\)
顺带:\(x^{\overline n}=(-1)^n(-x)^{\underline n},x^{\underline n}=(-1)^n(-x)^{\overline n}\)
\(x^n=\sum\limits_{k=0}^x \begin{Bmatrix}n\\ k \end{Bmatrix} k!{x \choose k}\) ,即\(x^n=\sum\limits_{k=0}^x \begin{Bmatrix}n\\ k \end{Bmatrix}\times x^{\underline k}\)
\(x^n\) 为\(n\) 个有区别的小球丢进\(x\) 个有区别的盒子,允许空盒子;枚举有效盒子的个数,再从\(x\) 个盒子选\(k\) 个盒子,然后\(n\) 个小球丢进\(k\) 个盒子。
\(m^n=\sum\limits_{i=0}^{m}\begin{Bmatrix}n\\ i\end{Bmatrix}i!{m \choose i}\)
二项式反演一下:
\(m!\begin{Bmatrix}n\\ m\end{Bmatrix}=\sum\limits_{k=0}^m(-1)^{k} {m\choose k}(m-k)^n\)
理解:如果空箱子的情况我们也算进去,答案显然是\(\frac{m^n}{m!}\) ;反过来求第二类斯特林数,又得减掉这种情况:
- 选\(k\) 个空盒子,然后小球放到其他的盒子里
- 但最后我们求出来的答案为有区别的盒子,转换过来要\(\times \frac{1}{m!}\)
求解
求解\(\begin{Bmatrix}n\\ k \end{Bmatrix}\)
\(\begin{aligned}\begin{Bmatrix}n\\ m\end{Bmatrix}&=\frac{1}{m!}\sum\limits_{k=0}^m(-1)^k\frac{m!}{k!(m-k)!}(m-k)^n\\ &=\sum\limits_{k=0}^m\frac{(-1)^k(m-k)^n}{k!(m-k)!}\end{aligned}\)
发现可以卷积求出\(n\) 一行的斯特林数。
#include<iostream>
#include<cstdio>
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
} const int N=800010,G=3,Gi=55924054,M=167772161;
int n,K,len,ans;
int fac[N],Inv[N],a[N],b[N],p[N];
inline int qpow(int a,int b) { R ret=1;
for(;b;b>>=1,a=1ll*a*a%M) if(b&1) ret=1ll*ret*a%M; return ret;
}
inline void ntt(int* a,int op) {
for(R i=0;i<K;++i) if(i<p[i]) swap(a[i],a[p[i]]);
for(R l=1;l<K;l<<=1) { R g1=qpow(~op?G:Gi,(M-1)/(l<<1)),gn,x,y;
for(R len=l<<1,i=0;i<K;i+=len) { gn=1;
for(R j=0;j<l;++j,gn=1ll*gn*g1%M)
x=a[i+j],y=1ll*a[i+j+l]*gn%M,a[i+j]=(x+y)%M,a[i+j+l]=(x-y+M)%M;
}
}
}
inline void main() {
n=g();
fac[0]=fac[1]=Inv[0]=Inv[1]=1;
for(R i=2;i<=n;++i) fac[i]=1ll*fac[i-1]*i%M;
Inv[n]=qpow(fac[n],M-2);
for(R i=n-1;i>=2;--i) Inv[i]=1ll*Inv[i+1]*(i+1)%M;
K=1; while(K<=n*2) K<<=1,++len;
for(R i=0;i<K;++i) p[i]=(p[i>>1]>>1)|((i&1)<<(len-1));
for(R i=0;i<=n;++i) a[i]=1ll*(i&1?M-1ll:1ll)*Inv[i]%M;
for(R i=0;i<=n;++i) b[i]=1ll*qpow(i,n)*Inv[i]%M;
ntt(a,1),ntt(b,1);
for(R i=0;i<K;++i) a[i]=1ll*a[i]*b[i]%M;
ntt(a,-1); R inv=qpow(K,M-2);
for(R i=0;i<=n;++i) a[i]=1ll*a[i]*inv%M;
for(R i=0;i<=n;++i) printf("%d ",a[i]);
}
} signed main() {Luitaryi::main(); return 0;}
与自然数幂的关系
\(\begin{aligned} Sum(n)&=\sum\limits_{i=0}^n i^k\\ &=\sum\limits_{i=0}^n\sum\limits_{j=0}^k\begin{Bmatrix}k\\ j \end{Bmatrix}i^{\underline j}\\ &=\sum\limits_{j=0}^k\begin{Bmatrix}k\\ j \end{Bmatrix}\sum\limits_{i=0}^n i^{\underline j}\\ &=\sum\limits_{j=0}^k \begin{Bmatrix}k\\ j \end{Bmatrix}j!\sum\limits_{i=0}^n{i\choose j}\\ &=\sum\limits_{j=0}^k \begin{Bmatrix}k\\ j \end{Bmatrix}j!{n+1 \choose j+1}\\ &=\sum\limits_{j=0}^k \begin{Bmatrix}k\\ j \end{Bmatrix} \frac{(n+1)^{\underline {j+1}}}{j+1}\end{aligned}\)
斯特林反演
反转公式
\(\sum\limits_{k=m}^n (-1)^{n-k}\begin{bmatrix}n\\ k\end{bmatrix} \begin{Bmatrix}k\\ m\end{Bmatrix}=[m=n]\\ \sum\limits_{k=m}^n (-1)^{n-k}\begin{Bmatrix}n\\ k\end{Bmatrix} \begin{bmatrix}k\\ m\end{bmatrix}=[m=n]\)
证明:
\(\begin{aligned}m^{\underline n}&=\sum\limits_{i=0}^n \begin{bmatrix}n\\ i\end{bmatrix}(-1)^{n-i}m^i\\ &=\sum\limits_{i=0}^n \begin{bmatrix}n\\ i\end{bmatrix}(-1)^{n-i}\sum\limits_{j=0}^i \begin{Bmatrix}i\\ j\end{Bmatrix}m^{\underline j}\\ &=\sum\limits_{i=0}^n m^{\underline i}\sum\limits_{j=i}^n (-1)^{n-j} \begin{bmatrix}n\\ j\end{bmatrix} \begin{Bmatrix}j\\ i\end{Bmatrix}\end{aligned}\)
\(\begin{aligned}m^n&=\sum\limits_{i=0}^n\begin{Bmatrix}n\\ i\end{Bmatrix}m^{\underline i}\\ &=\sum\limits_{i=0}^n\begin{Bmatrix}n\\ i\end{Bmatrix}(-1)^i(-m)^{\overline i}\\ &=\sum\limits_{i=0}^n\begin{Bmatrix}n\\ i\end{Bmatrix}(-1)^i\sum\limits_{j=0}^i \begin{bmatrix}i\\ j\end{bmatrix}(-m)^j\\ &=\sum\limits_{i=0}^n m^i\sum\limits_{j=i}^n(-1)^{i-j} \begin{Bmatrix}n\\ j\end{Bmatrix}\begin{bmatrix}j\\ i\end{bmatrix}\end{aligned}\)
斯特林反演
设\(g_n=\sum\limits_{k=0}^n(-1)^{n-k}\begin {bmatrix} n\\ k \end{bmatrix}f_k\) 。
\(\begin{aligned} f_n&=\sum\limits_{k=0}^n [k=n]f_k\\ &=\sum\limits_{k=0}^n\sum\limits_{j=k}^n \begin {Bmatrix} n\\ j \end{Bmatrix}\begin {bmatrix} j\\ k \end{bmatrix}(-1)^{j-k}f_k\\ &=\sum\limits_{k=0}^n \begin {Bmatrix} n\\ k \end{Bmatrix}\sum\limits_{j=0}^k (-1)^{k-j}\begin {bmatrix} k\\ j \end{bmatrix}f_j\\ &=\sum\limits_{k=0}^n \begin {Bmatrix} n\\ k \end{Bmatrix}g_k \end{aligned}\)