组合数学基础
本文部分运用到了生成函数的知识
如果直接食用本文结论,请忽略下列链接。
生成函数参考博客:普通型生成函数 - Ricky2007 - 博客园
我认为讲的不错
组合数学非常有用!我们先从一点点简单的性质开始
简单原理
-
加法原理
这非常简单,我们举一个例子即可:考虑我有 5 个红苹果和 3 个绿苹果,如果你要选一个苹果去吃,那么你一共有 5+3=8 种选择的方法
-
乘法原理
同样非常简单:考虑我有 5 个苹果,涵儿有 6 个苹果,我们各自拿出一个苹果,那么一共有 5×6=30 种拿出的方案
-
减法原理和除法原理
本质与加法原理和乘法原理相似,这里不做展开
-
抽屉原理
(广义)如果 n 个物品一共有 k 种状态,那么至少有 ⌈nk⌉ 种物品处于一个状态
推论:一个从有 >k 个元素的集合映射到 k 个元素的集合的函数一定不是一对一函数。
终于正式开始将排列组合了!
排列
定理:具有 n 个元素的集合,选出 r 个排列的可能数(顺序相关)
P(n,r)=n(n−1)(n−2)⋯(n−r+1)
证明:由于顺序相关,不能选择同一个数多次,那么第一个位置有 n 种选法,第二个位置有 n−1 中选法,以此类推,第 i 个位置有 n−i+1 种选法。考虑乘法原理,那么就得出了上述结论。
特殊的:只要 n 是一个非负整数,那么 P(n,0)=1,因为恰好有一种方法来排列 0 个元素
简写公式:一般来说,我们不会写成上述形式,而是
P(n,r)=n!(n−r)!
多重排列
考虑这样一个问题:我有 7 个盘子,2 个苹果,3 个橘子和 2 个桃子,分别在一个盘子中放一个水果,一共有多少种放法(我们认为同一种水果是相同的)?
经过计算,一共有 7!2!3!2!=210 种放法。
抽象来说,我们将 k 个元素进行排列,对于第 i 个元素一共有 xi 个。那么总的排列方案数为
(x1+x2+⋯+xk)!x1!x2!⋯xk!
组合
其实就是顺序无关的排列
定理:具有 n 个元素的集合,选出 r 个数组成新的集合,本质不同的集合数为
C(n,r)=(nr)=n!r!(n−r)!
由于顺序无关,我们考虑通过排列推导。
证明:为了得出所有集合,我们先考虑顺序相关,也就是有 P(n,r) 个排列,而对于每一个排列,如果不考虑顺序,一共重复计算了 P(r,r) 次,所以
C(n,r)=P(n,r)P(r,r)=n!(n−r)!r!(r−r)!=n!r!(n−r)!
性质
接下来我们考虑组合的各种性质
(nm)=(nn−m)=nm(n−1m−1)=(n−1m)+(n−1m−1)
(nk)(km)=(nm)(n−km−k)
证明:展开即可
n∑i=k(ik)=(n+1k+1)
证明:还是考虑展开
n∑i=k(ik)=(kk+1)+(kk)+(k+1k)+⋯+(nk)
(kk+1) 是不合法的,所以其值为 0,加上去之后不会对结果产生影响
我们通过公式 (nm)=(n−1m)+(n−1m−1) 两两合并即可。
推论:我们将 i 平移,那么得出
m∑i=0(k+ii)=(k+m+1m+1)
接下来是剩下的一个最重要的二项式系数恒等式:
(rk)=(−1)k(k−r−1k)
这是上指标反转,需要用到广义组合数的知识。
广义组合数:
定义下降幂 xn––=x(x−1)⋯(x−n+1),那么我们可以定义广义组合数:
(rk)=rk––k!
其是一个关于 r 的 k 次多项式,注意 k∈N。
于是考虑 xn––=x(x−1)⋯(x−n+1)=(−1)n(0−x)(1−x)⋯(n−1−x)=(−1)n(n−1−x)n––,这就是上指标反转的来源。
我们总结一下这 10 个最最重要的等式:
(nk)=nk––k!(nk)=(nn−k)(nk)=(n−1k)+(n−1k−1)(nm)(mk)=(nk)(n−km−k)(x+y)r=∑k(rk)xkyr−k(nm)=(−1)m(m−n−1m)n∑k=0(km)=(n+1m+1)m∑k=0(n+kk)=(n+m+1m)∑k(nk)(ms−k)=(n+ms)(rk)=(−1)k(k−r−1k)
小练习
n∑i=0i(ni)=n2n−1
证明:
考虑代数展开,通过 (nm)=(nn−m) 变化即可。
n∑i=0i(ni)=0(n0)+1(n1)+⋯+(n−1)(nn−1)+n(nn)
但是,其实可以通过生成函数推导。推导步骤如下:
我们先展开,得到
0+1(n1)+2(n2)+⋯+n(nn)
我们可以由此联想到生成函数求导的公式
<a1,a2,a3,⋯>→<a2,2a3,3a4,⋯>
那么我们考虑求导前的生成函数序列:
<(n0),(n1),(n2),…,(nn),0,⋯>
显然,其生成函数展开之前为 F(x)=(1+x)n
那么我们对其求导得到 F′(x)=n(1+x)n−1
展开之后为
<1(n1),2(n2),3(n3),…,n(nn),0,⋯>
我们考虑需要把所有的系数加起来,那么我们令 x=1 即可
所以,得出
n∑i=0i(ni)=F′(1)=n(1+1)n−1=n2n−1
我们考虑扩展一下上述式子
n∑i=0i2(ni)=n2n−1+(n−1)n2n−2
考虑还是利用生成函数的思路。
将生成函数 F′(x)=n(1+x)n−1 向右平移一位并再次求导:
G(x)=xF′(x)=nx(1+x)n−1G′(x)=n(1+x)n−1+(n−1)nx(1+x)n−2
那么我们还是借上面的思路,令 x=1,所以
n∑i=0i2(ni)=G′(1)=n2n−1+(n−1)nx(1+x)n−2=n2n−1+(n−1)n2n−2
二项式定理
定理:令 n 是非负整数,那么有
(x+y)n=n∑i=0(ni)xn−iyi=(n0)xny0+(n1)xn−1y1+⋯+(nn−1)x1yn−1+(nn)x0yn
考虑展开之后每一项都应该是 n 次的,所以 x 为 i 次一共有 (ni) 种情况
求 ∑k≤n(nk)2k−n 分别在 k,n 作为变量时的封闭形式。
先将 n<0 的情况特判掉。
很简单的是将 2−n 提出来,利用二项式定理合并即可:
2−n∑k≤n(nk)2k=2−n3n
先将 k<0 的情况特判掉。
略微复杂一点的是我们需要用到上指标反转。
∑n(nn−k)2k−n=∑n(−1)n−k(−k−1n−k)2−(n−k)=∑n(−k−1n−k)(−12)n−k=(1−12)−k−1=2k+1
注意这里使用了广义二项式定理!
广义二项式定理可以将 n 次扩展到全体实数上,其描述为对于 α∈R:
(x+y)α=∑k(αk)xkyα−k
这是非常好用的东西!
小练习
当整数 m,n>0 时,求出下式的封闭形式:
∑k≥1(n⌊logmk⌋)
这与二项式定理真的有关系吗?天知道!
我们枚举 ⌊logmk⌋ 的取值:
∑j≥0(nj)∑k[⌊logmk⌋=j]=∑j≥0(nj)∑k[mj≤k<mj+1]=∑j≥0(nj)(mj+1−mj)=(m−1)∑j≥0(nj)mj=(m−1)(m+1)n
怎么样,很简单吧。
我们对于阶乘下降幂实际上有一个很类似的结果:
(x+y)n––=∑k(nk)xk––yn−k–––––
证明可以采用归纳法,这里就不展开了。
范德蒙德卷积
已知 n,m,t 其中 t 是整数:
t∑i=0(ni)(mt−i)=(n+mt)
证明:在组合意义上,相当于在 n 中选 i 个,在 m 中选剩下的,也就是在 n+m 中选择 t 个。
而二项式证明这里就不展开了。
小练习
请证明:
n∑i=0(ni)2=(2nn)
扩展
范德蒙德卷积有着更为变化的形式:
s≥0→∑k(sk)(tm+k)=(s+tt−m)s≥0→∑k(−1)k(sm+k)(t+kn)=(−1)s+m(t−mn−s)l,m,n≥0→∑k≤l(l−km)(sk−n)(−1)k=(−1)l+m(s−m−1l−m−n)m,n≥0,l+q≥0→∑−q≤k≤l(l−km)(q+kn)=(l+q+1m+n+1)
这些式子都可以通过种种神秘的方法进行推导,此处不展开。
Lucas定理
定理:
(nm)≡(⌊np⌋⌊mp⌋)(n%pm%p)(modp)
这个证明相对复杂,请酌情食用
证明:
我们考虑通过带余方程改写上述式子:
(sp+tkp+r)≡(sk)(tr)(modp)
我们通过生成函数 F(x)=(1+x)sp+t 的第 kp+r 次项的系数求。
我们先求一个推导的时候需要的东西:
(1+x)p≡1+(p1)x+(p2)x2+(p3)x3+⋯+(pp−1)xp−1+xp(modp)≡1+xp(modp)
那么我们正式开始推导:
(1+x)sp+t≡(1+x)sp⋅(1+x)t(modp)≡((1+x)p)s⋅(1+x)t≡(1+xp)s⋅(1+x)t≡s∑i=0(si)xpi⋅t∑j=0(tj)xj
我们取 xkp+r 项
那么当且仅当 i=k,j=r 时,就可以取出 xkp+r 项的系数。
考虑为什么当且仅当?
可知,我们需要 ip+j=kp+r
∵j∈[0,t],t∈[0,p),r∈[0,p)∴j=r,i=k
那么,其系数为
(sk)(tr)
所以,可知
(sk)(tr)≡(sp+tkp+r)(modp)
得证:
(nm)≡(⌊np⌋⌊mp⌋)(n%pm%p)(modp)
程序实现:
这里还是稍微讲一下吧
首先,我们需要求出组合数,那么我们先预处理一下模数以内的阶乘和阶乘逆元:
long long fac[N], ifac[N];
for (int i = fac[0] = 1; i < MOD; ++i) fac[i] = (i * fac[i - 1]) % MOD;
ifac[MOD - 1] = quickPow(fac[MOD - 1], MOD - 2, MOD);
for (int i = MOD - 1; i; --i) ifac[i - 1] = ifac[i] * i % MOD;
考虑一下组合数的特殊情况,如果 n<m 那么 (nm)=0
所以我们求模数以内的组合数方法如下:
inline int C(int i, int j) {
return (i < j || j < 0) ? 0 : fac[i] * ifac[j] % MOD * ifac[i - j] % MOD;
}
那么Lucas定理呢?我们处理一下 n=0 的特殊情况即可
inline int Lucas(int i, int j) {
if (j == 0) return 1;
return Lucas(i / MOD, j / MOD) * C(i % MOD, j % MOD) % MOD;
}
广义容斥与二项式反演
这个部分相对较复杂,我给出反演公式
令 fn 表示之多拥有 n 个属性的集合个数,gn 表示恰好拥有 n 个属性的集合
那么
fn=n∑i=0(ni)gign=n∑i=0(−1)n−i(ni)fi
反演推导证明
gn=n∑i=0(−1)n−i(ni)i∑j=0(ij)gj求和符号变换:=n∑j=0gjn∑i=j(ni)(ij)(−1)n−i=n∑j=0gjn∑i=j(nj)(n−ji−j)(−1)n−i=n∑j=0gj(nj)n∑i=j(n−ji−j)(−1)n−i=n∑j=0gj(nj)n−j∑i=0(n−ji)(−1)n−i=n∑j=0gj(nj)(1+(−1))n−j[当且仅当n=j时有贡献:(1+(−1))n−j≠0]=gj(nj)[n=j]=gn
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?