下降幂、斯特林数学习笔记
下降幂
注:这里其实还有上升幂。
定义
下降幂:\(x^{\underline{k}}=\prod\limits_{i=x-k+1}^xi=\frac{x!}{(x-k)!}\)
上升幂:\(x^{\overline{k}}=\prod\limits_{i=x}^{x+k-1}i=\frac{(x+k-1)!}{(x-1)!}\)
性质
幂相加:
上升幂、下降幂转化:
组合数、下降幂转化:
组合数转换:
下降幂、组合数相乘:
普通幂的牛顿二项式定理和下降幂、上升幂的二项式定理:
在微积分中的运用
大坑待补……
斯特林数
第二类斯特林数
定义
定义 \(\begin{Bmatrix}n\\m\end{Bmatrix}\) 表示将 \(n\) 个数分到 \(m\) 个两两相同的集合中的方案数。我们称他为第二类斯特林数。
递推公式
考虑我们新加入一个数产生的贡献。
- 放入一个新的集合。那么原先就有 \(m-1\) 个集合,产生 \(\begin{Bmatrix}n-1\\m-1\end{Bmatrix}\) 的贡献。
- 放入原先的 \(m\) 个集合中。那么有 \(m\) 种可能的方法,产生 \(m\begin{Bmatrix}n-1\\m\end{Bmatrix}\) 的贡献。
所以 \(\begin{Bmatrix}n\\m\end{Bmatrix}=\begin{Bmatrix}n-1\\m-1\end{Bmatrix}+m\begin{Bmatrix}n-1\\m\end{Bmatrix}\)。
通项公式
考虑容斥。由于两两相同的集合并不好处理,因此我们先让集合两两不同,最后再将算出的答案 \(\times\frac 1{k!}\) 即可。
设 \(f(x)\) 表示至少有 \(x\) 个空集合的情况,则有:
设 \(g(x)\) 表示恰好有 \(x\) 个空集合的情况,则有:
容易发现 \(\begin{Bmatrix}n\\m\end{Bmatrix}=\dfrac{g(0)}{m!}\),则有:
性质
普通幂转上升幂:
普通幂转下降幂:
通常第二种情形在组合数学中更常用,经常与 \(\binom nkk^{\underline i}=\binom{n-i}{k-i}n^{\underline i}\) 配套使用,用来提出下降幂。
第二类斯特林数·行
斯特林数中,一行指数的数量相同,一列指集合或圆排列数量相同。
对于第二类斯特林数·行这个问题,当然可以使用递推式 \(O(n^2)\) 求解,但是太慢了,考虑 NTT。
一眼 NTT 经典形态,\(O(n\log n)\) 光速解决。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=6e5+5,p=167772161;
namespace NTT{
int rev[N],mx,k,qp;
struct dft{int fg[N];};
int qpow(int x,int y){
int re=1;
while(y){
if(y&1) re=re*x%p;
x=x*x%p,y>>=1;
}return re;
}void init(int n){
mx=1,k=0,rev[0]=0;
while(mx<=n) mx*=2,k++;
for(int i=0;i<mx;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
qp=qpow(mx,p-2);
}void ntt(dft &a,int fl){
for(int i=0;i<mx;i++)
if(i<rev[i]) swap(a.fg[i],a.fg[rev[i]]);
for(int i=1;i<mx;i*=2){
int om=qpow(fl?3:(p+1)/3,(p-1)/(i<<1));
for(int j=0,w=1;j<mx;j+=i*2,w=1)
for(int k=j;k<j+i;k++,w=w*om%p){
int x=a.fg[k],y=w*a.fg[k+i]%p;
a.fg[k]=(x+y)%p,a.fg[k+i]=(x-y+p)%p;
}
}if(fl) return;
for(int i=0;i<mx;i++)
a.fg[i]=a.fg[i]*qp%p;
}
}using namespace NTT;
int n;dft f,g;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n,init(n*2+1);
for(int i=0,jc=1;i<=n;i++,jc=jc*i%p){
f.fg[i]=(1-i%2*2)*qpow(jc,p-2);
g.fg[i]=qpow(i,n)*qpow(jc,p-2)%p;
}ntt(f,1),ntt(g,1);
for(int i=0;i<mx;i++)
f.fg[i]=f.fg[i]*g.fg[i]%p;
ntt(f,0);
for(int i=0;i<=n;i++)
cout<<f.fg[i]<<" ";
return 0;
}
第二类斯特林数·列
大坑待补……
第一类斯特林数
注:第一类斯特林数没有实用的通项公式。
定义
定义 \(\begin{bmatrix}n\\m\end{bmatrix}\) 表示将 \(n\) 个数分到 \(m\) 个两两相同的圆排列中的方案数。我们称他为第一类斯特林数。
递推公式
考虑我们新加入一个数产生的贡献。
- 放入一个新的圆排列。那么原先就有 \(m-1\) 个圆排列,产生 \(\begin{bmatrix}n-1\\m-1\end{bmatrix}\) 的贡献。
- 放入原先的 \(m\) 个集合中。那么有 \(n-1\) 种可能的方法,产生 \((n-1)\begin{bmatrix}n-1\\m\end{bmatrix}\) 的贡献。
所以 \(\begin{bmatrix}n\\m\end{bmatrix}=\begin{bmatrix}n-1\\m-1\end{bmatrix}+(n-1)\begin{bmatrix}n-1\\m\end{bmatrix}\)。
性质
上升幂转普通幂:
下降幂转普通幂:
第一类斯特林数·行
大坑待补……
第一类斯特林数·列
大坑待补……
斯特林反演
先放公式:
两个证明相似,这里只证明第一个。考虑:
由于等式两端恒等,所以满足:
假如我们分解的是 \(m^{\underline n}\),那么会有:
现在我们就可以开始证明反演公式了:
当 \(g(n)=\sum\limits_{i=0}^n(-1)^i\begin{bmatrix}n\\i\end{bmatrix}f(i)\) 时,有:
那我们就完成了右到左的推导。假如 \(f(n)=\sum_{i=0}^n\begin{Bmatrix}n\\i\end{Bmatrix}g(i)\) 的话,那么有:
换元就和上面一样了。
另外一个公式也差不多,于是我们就证明了斯特林反演公式:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)