TonyYin's Blog

Back

第二类斯特林数#

定义#

第二类斯特林数,用 S(n,m)S(n,m){nm}\begin{Bmatrix}n\\m\end{Bmatrix} 表示:将 nn 个有标号元素分为 mm非空 无标号集合的方案数。

递推式#

{nm}={n1m1}+m×{n1m}\begin{Bmatrix}n\\m\end{Bmatrix}=\begin{Bmatrix}n-1\\m-1\end{Bmatrix} + m\times \begin{Bmatrix}n-1\\m\end{Bmatrix}

通项公式#

{nm}=i=0min(1)mii!(mi)!\begin{Bmatrix}n\\m\end{Bmatrix}=\sum_{i=0}^{m} \frac{i ^ n(-1)^{m-i}}{i!(m-i)!}

#

nn 固定,mm 变。

注意到通项公式很像卷积式,直接设:

[ni]g(n)=ini!,[ni]h(n)=(1)ii![n^i]g(n)=\dfrac{i^n}{i!}, [n^i]h(n)=\dfrac{(-1)^{i}}{i!}

由于通项公式中 i+(mi)=mi + (m-i) = m,直接卷积得到 f=ghf=g*h.

Poly A, B;
A.a.resize(n+1), B.a.resize(n+1);
for(int i = 0; i <= n; i++) A.a[i] = power(i, n) * fac_inv[i] % mod;
for(int i = 0; i <= n; i++) B.a[i] = (i&1) ? mod - fac_inv[i] : fac_inv[i];
A = A * B;
cpp

#

TODO.

第一类斯特林数#

定义#

第一类斯特林数,用 s(n,m)s(n,m)[nm]\begin{bmatrix}n\\m\end{bmatrix} 表示:将 nn 个有标号元素分为 mm非空无标号圆排列的方案数。

递推式#

[nk]=[n1k1]+(n1)[n1k]\begin{bmatrix}n\\k\end{bmatrix}=\begin{bmatrix}n-1\\k-1\end{bmatrix}+(n-1)\begin{bmatrix}n-1\\k\end{bmatrix}

#

https://www.luogu.com.cn/blog/oylyer/solution-p5408

记:

Fn(x)=xn=i=0n(x+i)F_n(x)=x^{\overline n}=\prod_{i=0}^n (x+i)

则可证:

xn=i=1n[ni]xix^{\overline n}=\sum_{i=1}^n \begin{bmatrix}n\\i\end{bmatrix} x^i

由于显然有 x2n=xn(x+n)nx^{\overline{2n}}=x^{\overline n}(x+n)^{\overline n},考虑分治求解。

Fn(x+n)=i=1n[ni](x+n)i=i=1n[ni]j=0i(ij)xjnij=i=1n[ni]j=0ii!j!(ij)!xjnij=j=0nxj1j!i=jn[ni]i!nij(ij)!\begin{aligned} F_n(x+n) &=\sum_{i=1}^n \begin{bmatrix}n\\i\end{bmatrix} (x+n)^i\\ &=\sum_{i=1}^n\begin{bmatrix}n\\i\end{bmatrix}\sum_{j=0}^i \binom{i}{j}x^jn^{i-j}\\ &=\sum_{i=1}^n\begin{bmatrix}n\\i\end{bmatrix}\sum_{j=0}^i \frac{i!}{j!(i-j)!}x^jn^{i-j}\\ &=\sum_{j=0}^n x^j \frac{1}{j!} \sum_{i=j}^n\begin{bmatrix}n\\i\end{bmatrix} i!\frac{n^{i-j}}{(i-j)!}\\ \end{aligned}

Ai=[ni]i!A_i=\begin{bmatrix}n\\i\end{bmatrix} i!Bi=nii!B_i=\dfrac{n^i}{i!},则原式化为:

Fn(x+n)=j=0ixj1j!i=1n[ni]i!nij(ij)!=j=0ixj1j!i=1nAiBij\begin{aligned} F_n(x+n) &=\sum_{j=0}^i x^j \frac{1}{j!} \sum_{i=1}^n\begin{bmatrix}n\\i\end{bmatrix} i!\frac{n^{i-j}}{(i-j)!}\\ &=\sum_{j=0}^i x^j \frac{1}{j!} \sum_{i=1}^n A_iB_{i-j}\\ \end{aligned}

要凑卷积的形式,把 BB 翻转得到 Bni=BiB^{\prime}_{n-i}=B_i,则:

Fn(x+n)=j=0ixj1j!i=1nAiBij=j=0ixj1j!i=1nAiBn+ji\begin{aligned} F_n(x+n) &=\sum_{j=0}^i x^j \frac{1}{j!} \sum_{i=1}^n A_iB_{i-j}\\ &=\sum_{j=0}^i x^j \frac{1}{j!} \sum_{i=1}^n A_i{B^{\prime}}_{n+j-i}\\ \end{aligned}

这样 ABA*{B^{\prime}} 之后,得到的 n+jn+j 次项系数左移 nn 位,再整体 ×1j!\times \frac{1}{j!},就是 Fn(x+n)F_n(x+n)jj 次项系数。

再把 Fn(x)Fn(x+n)F_n(x)*F_n(x+n),即可得到 F2n(x)F_{2n}(x)

注意分治过程中,F2n+1=Fn(x)Fn(x+n)(x+2n)F_{2n+1}=F_n(x)*F_n(x+n)*(x+2n),遇到奇数就手动乘上去即可。

void solve(int x) { //求f(x)
	//x的一次上升幂f(x)=x,零次项系数为0,一次项系数为1
	if(x == 1) { F.a.resize(2); F.a[1] = 1; return; }
	//递归,通过f(n)求出f(x)
	solve(x >> 1);
	int n = (x >> 1);
	//计算出A、B
	A.a.resize(n+1), B.a.resize(n+1);
	for(int i = 0; i <= n; i++) A.a[i] = F.a[i] * fac[i] % mod;
	for(int i = 0, pw = 1; i <= n; i++, pw = pw * n % mod) 
        B.a[i] = pw * fac_inv[i] % mod;
	reverse(B.a.begin(), B.a.begin() + n + 1);
	//A与B卷积,把第n+1~2n位向左平移,之后A的每项系数除以阶乘,F再卷上A
	A = A * B;
	for(int i = 0; i <= n; i++) A.a[i] = A.a[i + n];
	for(int i = 0; i <= n; i++) A.a[i] = A.a[i] * fac_inv[i] % mod;
	A.a.resize(n+1);
	F = A * F;
	//若x是奇数,则2*n=x-1,上升幂需要再卷上一个(x+2*n),左移,每个系数都乘上2*n
	if(x & 1) {
		F.a.resize(2 * n + 2);
		for(int i = 2 * n + 1; i >= 1; i--) 
            F.a[i] = (F.a[i - 1] + (x - 1) * F.a[i] % mod) % mod;
		F.a[0] = F.a[0] * (x - 1) % mod;
	}
}
cpp

#

TODO。

斯特林数
https://www.tonyyin.top/blog/oi-notes/stirling
Author TonyYin
Published at March 2, 2022
Comment seems to stuck. Try to refresh?✨