【学习笔记】【数学】斯特林数基础

斯特林数基础

高等的我不会

点击查看目录

前置知识:

  • 组合数学

  • 容斥原理(证明第二类斯特林数的通项公式)

  • 二项式反演(证明第二类斯特林数的通项公式)

  • 圆排列相关(第一类斯特林数)

圆排列相关

循环排列,又称圆排列,环排列,轮换。

\(m\) 个数中选 \(n\) 个不同的元素排列成一个无头无尾的环形,两个圆排列相同当且仅当索取元素个数相同,取法一致,环上排列顺序相同。

如:\(abcde,bcdea,cdeab,deabc,eabcd\) 是五个元素的一种圆排列。

\(acbde\) 则又是另一种圆排列,这是圆排列与直线排列的主要区别。

而根据刚刚我们知道,一种圆排列可以拆成五种不同的直线排列,而五个元素的直线排列有 \(5!\) 种,设圆排列个数为 \(x\),易得:

\[ \begin{aligned} x=\frac{5!}{5}=(5-1)!=4! \end{aligned} \]

即,对于 \(n\) 个不同的元素,其圆排列个数为 \((n-1)!\)

而我们知道,\(m\) 个相异元素里,选出 \(n\) 个数的方案数是 \(\dbinom{m}{n}\)

因此,从 \(m\) 个相异元素选出 \(n\) 个可以组成圆排列个数:

\[ \begin{aligned} x=\dbinom{m}{n}\times (n-1)!=\frac{A_m^n}{n} \end{aligned} \]

  • 上升幂与下降幂(通过斯特林数转换普通幂)
上升幂、下降幂

上升幂与下降幂怎么来的我就不知道了,好像是微积分?

来自微积分

定义下降幂$ x^{\underline{m}}$,上升幂 \(x^{\overline{m}}\),有:

\[ \begin{aligned} &x^{\underline m} = x(x - 1)(x - 2) ... (x - m + 1)\\ &x^{\overline m} = x(x + 1)(x + 2) ... (x + m - 1) \end{aligned} \]

他们之间有关联:

\[ \begin{aligned} &(-x)^{\underline m}=(-1)^m\times x^{\overline m}\\ &(-x)^{\overline m}=(-1)^m\times x^{\underline m} \end{aligned} \]

我认为这是显然的,读者自证不难(

小小的证明一下:

\[ \begin{aligned} (-x)^{\underline m}&=(-x)(-x-1)(-x-2)…(-x-m+1)\\ &=(-1)^m\times x(x+1)(x+2)…(x+m-1)\\ &=(-1)^m\times x^{\overline m} \end{aligned} \]

相应的,排列组合数也和二项式有关:

\[ \begin{aligned} &\dbinom{n}{m}=\frac{n!}{m!(n-m)!}=\frac{n^{\underline m}}{m!}\\ &A_n^m=\frac{n!}{(n-m)!}=n^{\underline m} \end{aligned} \]

甚至有非常奇妙的有关同余的性质:

\[ \begin{aligned} x^{\overline m}\equiv x^m-x\pmod{m} \end{aligned} \]

但是没什么用好像,也不是很想证明了,留给佬的闲话(什

证了的话可以@我谢谢喵

  • 数学归纳法(通过斯特林数转换普通幂)
有关数学归纳法

数学归纳法是证明某个命题对于所有满足 \(n\geq n_0\) 的整数 \(n\) 的都成立的一种方法,具体步骤如下:

  • 首先在 \(n\) 取得最小值 \(n_0\) 时证明命题,即基础

  • 其次对 \(n>n_0\),假设 \(n_0\)\(n-1\) 之间(包括它们本身)所有值都已经被证明,证明该命题对 \(n\) 成立,即归纳

用有限步可以得到无限的结果,这就是数学归纳!

往往递推式可以用数学归纳法完美地建立。

定义:

百度百科

oi-wiki

斯特林数,多出现在组合枚举问题中。

  • 第一类斯特林数 \(s(n,m)\),也被记为 \(\begin{bmatrix}n\\m \end{bmatrix}\),表示将 \(n\) 个不同元素构成 \(m\) 个圆排列的方案数。

  • 第二类斯特林数 \(S(n,m)\),也被记为 \(\begin{Bmatrix}n\\m \end{Bmatrix}\),表示将 \(n\) 个不同元素分成 \(m\) 个集合的方案数。

由于第一类斯特林数与第二类斯特林数的 \(s\) 大小写难以区分,所以本文将采用另一种写法。

通常第二类斯特林数更加常用,因此首先描述第二类斯特林数。

第二类斯特林数

第二类斯特林数(斯特林子集数)\(\begin{Bmatrix}n\\k \end{Bmatrix}\),表示将 \(n\) 个相异元素划分为 \(k\) 个互不区分的非空子集的方案数。

(互不区分:不考虑非空子集之间的排列)

递推式:

\[ \begin{aligned} \begin{Bmatrix}n\\k \end{Bmatrix}=\begin{Bmatrix} n-1\\k-1 \end{Bmatrix}+k\times\begin{Bmatrix} n-1\\k \end{Bmatrix} \end{aligned} \]

边界为 \(\begin{Bmatrix} n\\0 \end{Bmatrix}=[n=0]\)

(\([n=0]\) 返回值是一个 bool 值)

证明:

  • 这是一个递推式,我们每新加入一个新元素,将新元素单独开一个子集,有\(\begin{Bmatrix} n-1\\k-1 \end{Bmatrix}\) 种方案。

  • 将新元素放入一个现有的非空子集,有 \(k\times \begin{Bmatrix} n-1\\k \end{Bmatrix}\) 种方案。

加法原理相加。

最后边界是 \(\begin{Bmatrix} n\\0 \end{Bmatrix}=[n=0]\),毫无疑问如果 \(n\neq 0\) 是无意义的,否则方案数为 \(1\)

于是有递推代码:

递推求第二类斯特林数
#define rg register int
#define il inline
il void pre(){
//递推求至S[n][m] 
	S[0][0]=1;
	for(rg i=1;i<=n;++i){
		for(rg j=1;j<=min(i,m);++j){
			S[i][j]=S[i-1][j-1]+j*S[i-1][j]%mod;
		}
	}
} 

通项公式

\[ \begin{aligned} \begin{Bmatrix} n\\m \end{Bmatrix}=\sum_{i=0}^{m}\limits\frac{(-1)^{m-i}\times i^n}{i!(m-i)!} \end{aligned} \]

这个公式可以用容斥原理或二项式反演证明,这里使用二项式反演:

\(n\) 个互异元素,划分到 \(i\) 个互异集合(包括空集)的方案数是 \(g_i=i^n\),而 \(n\) 个互异元素,划分至 \(i\) 个两两不同的非空集合(不包括空集)的方案数是 \(f_i\)

根据二项式反演形式一:\(f_n=\sum^{n}_{i=0}\limits \dbinom{n}{i}g_i \Leftrightarrow g_n=\sum^{n}_{i=0}\limits(-1)^{n-i}\dbinom{n}{i}f_i\),易得:

\[ \begin{aligned} g_i&=\sum_{j=0}^{i}\limits \dbinom{i}{j} \times f_j\\ f_i&=\sum_{j=0}^{i}\limits (-1)^{i-j}\times \dbinom{i}{j} \times g_j\\ &=\sum_{j=0}^{i} (-1)^{i-j}\times \dbinom{i}{j} \times j^n\\ &=\sum_{j=0}^{i}\limits \frac{i!\times (-1)^{i-j}\times j^n}{j!\times (i-j)!} \end{aligned} \]

\(f_i\)\(\begin{Bmatrix} n\\i \end{Bmatrix}\) 的唯一不同点在于:\(\begin{Bmatrix} n\\i \end{Bmatrix}\) 不计算非空集合之间的排列,因此 \(f_i=i!\times \begin{Bmatrix} n\\i \end{Bmatrix}\),得证:

\[\begin{aligned} \begin{Bmatrix} n\\m \end{Bmatrix}=\frac{f_m}{m!}=\sum_{i=0}^{m}\limits \frac{(-1)^{m-i}\times i^n}{i!\times (m-i)!} \end{aligned} \]

至于同一行第二类斯特林数之类的计算我不会,长大再学(

第一类斯特林数

第一类斯特林数(斯特林轮换数),\(\begin{bmatrix} n\\k \end{bmatrix}\),表示将 \(n\) 个相异元素划分为 \(k\) 个互不区分的非空的圆排列方案数。

(互不区分:不考虑非空子集之间的排列)

(有关圆排列已经在前置知识解释)

递推式

\[ \begin{aligned} \begin{bmatrix} n\\k \end{bmatrix}=\begin{bmatrix} n-1\\k-1 \end{bmatrix}+(n-1)\times \begin{bmatrix} n-1\\k \end{bmatrix} \end{aligned} \]

边界是 \(\begin{bmatrix} n\\0 \end{bmatrix}=[n=0]\)

(\([n=0]\) 返回值是一个 bool 值)

相似的证明:

当我们插入一个新元素的时候,有两种方案:

  • 新元素单独放入一个圆排列: \(\begin{bmatrix} n-1\\k-1 \end{bmatrix}\)

  • 新元素插入到任何一个现有的圆排列中:\((n-1)\times \begin{bmatrix} n-1\\k \end{bmatrix}\)

加法原理易证。

对于 \(\begin{bmatrix} n\\0 \end{bmatrix}=[n=0]\) 边界,\(n\leq 0\) 无意义,否则方案为 \(1\)

递推求第一类斯特林数
#define rg register int
#define il inline
il void pre(){
//递推求至s[n][m] 
	s[0][0]=1;
	for(rg i=1;i<=n;++i){
		for(rg j=1;j<=min(i,m);++j){
			s[i][j]=s[i-1][j-1]+(i-1)*s[i-1][j]%mod;
		}
	}
} 

同一行第一类斯特林数我不会,长大再学(

上升幂、下降幂与普通幂的转化

有恒等式:

\[ \begin{aligned} &x^{\overline n}=\sum_{k=0}^{n}\limits \begin{bmatrix} n\\k \end{bmatrix} \times x^k\\ &x^n=\sum_{k=0}^{n}\limits \begin{Bmatrix} n\\k \end{Bmatrix} \times (-1)^{n-k}x^{\overline k}\\ &x^{\underline n}=\sum_{k=0}^{n}\limits \begin{bmatrix} n\\k \end{bmatrix} \times (-1)^{n-k}x^k\\ &x^n=\sum_{k=0}^{n}\limits \begin{Bmatrix} n\\k \end{Bmatrix}\times x^{\underline k} \end{aligned} \]

如何证明?数学归纳法(前置知识有)。

首先假设我们认为:

\[ \begin{aligned} x^n=\sum_{k=0}^{n}\limits \begin{Bmatrix} n\\k \end{Bmatrix}x^{\underline k},n\in Z, n\geq 0 \end{aligned} \]

显然本式在 \(n=0\) 时成立,故假设本式在 \(0-(n-1)\) 区间成立,证明 \(n\) 是否成立。

(我只会这么证明,不要问我先辈是如何找到这个式子的,我真不会)

因为 \(x^{\underline {k+1}}=x^{\underline k}\times (x-k)\),所以 \(x\times x^{\underline k}=x^{\underline {k+1}}+kx^{\underline k}\)。(本式在下面第\(2\to 3\) 行使用)

(ps:在第 \(4\to 5\) 行中:设 \(\begin{Bmatrix} n-1\\k-1 \end{Bmatrix}\)\(k=0\) 的情况下等于 \(0\)\(\begin{Bmatrix} n-1\\k \end{Bmatrix}\)\(k=n\) 的情况下等于 \(0\)。)

因此得到:

\[ \begin{aligned} x^n&=x\times x^{n-1}\\ &=x\times \sum_{k=0}^{n-1}\limits \begin{Bmatrix} n-1\\k \end{Bmatrix}\times x^{\underline k}\\ &=\sum_{k=0}^{n-1}\limits \begin{Bmatrix} n-1\\k \end{Bmatrix}\times x^{\underline {k+1}}+\sum_{k=0}^{n-1}\limits \begin{Bmatrix} n-1\\k \end{Bmatrix}\times kx^{\underline k}\\ &=\sum_{k=1}^{n}\limits \begin{Bmatrix} n-1\\k-1 \end{Bmatrix}\times x^{\underline {k}}+\sum_{k=0}^{n-1}\limits \begin{Bmatrix} n-1\\k \end{Bmatrix}\times kx^{\underline k}\\ &=\sum_{k=0}^{n}\limits \begin{Bmatrix} n-1\\k-1 \end{Bmatrix}\times x^{\underline {k}}+\sum_{k=0}^{n}\limits \begin{Bmatrix} n-1\\k \end{Bmatrix}\times kx^{\underline k}\\ &=\sum_{k=0}^{n}\limits \left(k\times \begin{Bmatrix} n-1\\k \end{Bmatrix}+\begin{Bmatrix} n-1\\k-1 \end{Bmatrix}\right)x^{\underline k}\\ &=\sum_{k=0}^{n}\limits \begin{Bmatrix} n\\k \end{Bmatrix} x^{\underline k} \end{aligned} \]

证毕。

其余同理。

例题:Team Work

Team Work

题目链接

题面翻译

给定 $ n,k $,求:

\[\sum_{i=1}^n\binom n i \times i^k \]

$ 1 \leq k \leq 5000,1 \leq n \leq 10^9 $

题目描述

You have a team of $ N $ people. For a particular task, you can pick any non-empty subset of people. The cost of having $ x $ people for the task is $ x^{k} $ .

Output the sum of costs over all non-empty subsets of people.

输入格式

Only line of input contains two integers $ N $ $ (1<=N<=10^{9}) $ representing total number of people and $ k $ $ (1<=k<=5000) $ .

输出格式

Output the sum of costs for all non empty subsets modulo $ 10^{9}+7 $ .

样例 #1

样例输入 #1

1 1

样例输出 #1

1

样例 #2

样例输入 #2

3 2

样例输出 #2

24

提示

In the first example, there is only one non-empty subset $ {1} $ with cost $ 1^{1}=1 $ .

In the second example, there are seven non-empty subsets.

- $ {1} $ with cost $ 1^{2}=1 $

- $ {2} $ with cost $ 1^{2}=1 $

- $ {1,2} $ with cost $ 2^{2}=4 $

- $ {3} $ with cost $ 1^{2}=1 $

- $ {1,3} $ with cost $ 2^{2}=4 $

- $ {2,3} $ with cost $ 2^{2}=4 $

- $ {1,2,3} $ with cost $ 3^{2}=9 $

The total cost is $ 1+1+4+1+4+4+9=24 $ .

解题:

题意就是给你 \(n\) 个元素,你可以选任意几个元素组成的非空子集,选 \(x\) 个元素的代价是 \(x^k\)

要求输出所有非空子集的元素代价总和。

也就是要求输出答案 \(\sum_{i=1}^{n}\limits \dbinom{n}{i}\times i^k\)

\(\sum_{i=1}^{n}\limits \dbinom{n}{i}\times i^k=\sum_{i=0}^{n}\limits \dbinom{n}{i}\times i^k\)

对于 \(i^k\) 可以用第二类斯特林数展开:

推柿子:

\[ \begin{aligned} \sum_{i=0}^{n}\limits \dbinom{n}{i}\times i^k\\ &=\sum_{i=0}^{n}\limits \dbinom{n}{i}\sum_{j=1}^{k}\limits \begin{Bmatrix} k\\j \end{Bmatrix} \times i^{\underline j}\\ &=\sum_{i=0}^{n}\limits \dbinom{n}{i}\sum_{j=1}^{k}\limits \begin{Bmatrix} k\\j \end{Bmatrix} \times \frac{i!}{(i-j)!}\\ &=\sum_{i=0}^{n}\limits \dbinom{n}{i}\sum_{j=1}^{k}\limits \begin{Bmatrix} k\\j \end{Bmatrix} \times \frac{i!}{(i-j)!j!}\times j!\\ &=\sum_{i=0}^{n}\limits \dbinom{n}{i}\sum_{j=1}^{k}\limits \begin{Bmatrix} k\\j \end{Bmatrix} \times \dbinom{i}{j}\times j!\\ &=\sum_{j=1}^{k}\limits \begin{Bmatrix} k\\j \end{Bmatrix}j!\sum_{i=0}^{n}\limits \dbinom{n}{i}\times \dbinom{i}{j}\\ &=\sum_{j=1}^{k}\limits \begin{Bmatrix} k\\j \end{Bmatrix}j!\sum_{i=0}^{n}\limits \dbinom{n}{j}\times \dbinom{n-j}{i-j}\\ &=\sum_{j=1}^{k}\limits \begin{Bmatrix} k\\j \end{Bmatrix}j!\dbinom{n}{j}\sum_{i=0}^{n-j}\limits \dbinom{n-j}{i}\\ &=\sum_{j=1}^{k}\limits \begin{Bmatrix} k\\j \end{Bmatrix}j!\dbinom{n}{j}\sum_{i=0}^{n-j}\limits \dbinom{n-j}{i}\\ &=\sum_{j=1}^{k}\limits \begin{Bmatrix} k\\j \end{Bmatrix}j!\times \dbinom{n}{j}\times 2^{n-j}\\ &=\sum_{j=1}^{k}\limits \begin{Bmatrix} k\\j \end{Bmatrix} \frac{n!}{(n-j)!}\times 2^{n-j} \end{aligned} \]

\(\sum\)\(k\) 要取 \(min(n,k)\)

然后某些 OJ 有一些离谱数据,什么 \(n\leq 2\times 10^5,k\leq 10^9\) 之类的,因为 \(n\) 较小 \(k\) 过大,所以直接暴力过就行。

Miku's Code
#include<bits/stdc++.h>
using namespace std;
#define rg register int
#define il inline
#define int long long
typedef long double llf;
namespace mystd{
	il int Max(int a,int b){
		if(a<b)	return b;
		else	return a;
	}
	il int Min(int a,int b){
		if(a>b)	return b;
		else	return a;
	}
	il int Abs(int a){
		if(a<0)	return a*(-1);
		else	return a;
	}
}
const int maxn=2e5+50,mod=1e9+7;

int n,k,S[5000][5000];
int fac[maxn],inv[maxn],facinv[maxn];
int ans;

int qpow(int x,int y){
	int ans=1;
	while(y>0){
		if(y&1)	ans=(ans*x)%mod;
		x=(x*x)%mod;
		y=y>>1;
	}
	return ans%mod;
}

int getc(int y,int x,int m){
	if(x<y)	return 0;
	return fac[x]%m*facinv[y]%m*facinv[x-y]%m;
}

int lucas(int y,int x,int m){
	if(y==0)	return 1;
	return getc(y%m,x%m,m)%m*lucas(y/m,x/m,m)%m;
}

il void input(){
	scanf("%lld %lld",&n,&k);
}

il void pre(int w){
	S[0][0]=1,fac[0]=fac[1]=1;
	for(int i=1;i<=w;++i){
		fac[i]=i*fac[i-1]%mod;
		for(int j=1;j<=i;++j){
			S[i][j]=(S[i-1][j-1]+(int)j*S[i-1][j]%mod)%mod;
		}
	}
}

il void init(int maxp){
	fac[0]=fac[1]=1;
	inv[0]=inv[1]=1;
	facinv[0]=facinv[1]=1;
	for(int i=2;i<=maxp-1;++i){
		fac[i]=i*fac[i-1]%mod;
	}
	for(int i=2;i<=maxp-1;++i){
		inv[i]=(mod-mod/i*inv[mod%i]%mod+mod)%mod;
	}
	for(int i=2;i<=maxp-1;++i){
		facinv[i]=facinv[i-1]*inv[i]%mod;
	}
} 

signed main(){
	input();
	if(k<=5000){
		pre(k);
		for(int j=0;j<=min(n,k);++j){
			int res=0;
			res=(int)S[k][j]*qpow(2,n-j)%mod;
			for(int q=n-j+1;q<=n;++q){
				res=res*q%mod;
			}
			ans=(ans+res)%mod;
		}
		printf("%lld",ans);	
	} 
	else{
		init(2e5+50);
		for(int i=0;i<=n;++i){
			int res=0;
			res=lucas(i,n,mod)*qpow(i,k)%mod;
			ans=(ans+res)%mod; 
		}
		printf("%lld",ans);
		return 0;
	}
	return 0;
}

结束了,所有 latex 手打可能出错,若有错误请@我。

一次卷积以及反演我不会,长大再学(

upd on 10.7:集中修复部分 \(\LaTeX\) 问题。

posted @ 2023-08-07 17:29  Sonnety  阅读(372)  评论(6编辑  收藏  举报