组合数学是 OI 数学中的一个重要分支。在 OI 中有很多用途。具体包含排列,组合,以及衍生出来的特殊排列组合,和一些特殊的依托于组合数数列,如:卡特兰数,斯特林数等以及一些计数问题。
警告⚠:这篇博客里包含了大量的概念性用语,请注意梳理大脑信息。这里的证明有一些不是很严谨的地方和感性理解(换句话说,写了证明两个字并不一定真的在证明)。
加法原理与乘法原理
比较容易理解,完成一件事,有 n 类方法互不干扰,每类有 ai 种,方案数即为 ∑ai ;有 n 个步骤互不干扰,每个步骤有 ai 种,方案数为 ∏ai 。
排列组合公式
组合
Cnm 代表从 n 个数中选出 m 个元素组成集合。
Cnm(也可以写作(mn))=(n−m)!m!n!
组合数的性质(二项式推论)以及证明和应用
有些东西可能和后面有交叉。
(mn)=(n−mn)(1)
(1) 又称对称恒等式,感性理解即可,从 n 个里面选 m 个组成集合,那么剩下 n−m 个自然构成另一个集合。
(kn)=kn(k−1n−1)(2)
(2) 由定义式直接推导出即可。
(mn)=(mn−1)+(m−1n−1)(3)
(3) 增量法。从 n 个数里选 m 个,可以分成两种方法,
- 选第 m 个,在剩下的 n−1 个数中选 m−1 个。
- 不选第 m 个,在剩下的 n−1 个数中选 m 个。
组合数的递推式,可以 O(n2) 求组合数。
i=0∑k(in)(k−im)=(km+n)(n,m≥k)(4)
(4) 范德蒙公式。可以感性理解,从 n+m 个方案中选 m 个,可以分成两组,大小分别为 n 和 m ,从两组里共选 m 个。可以分别从两组里选 x 个和 y 个,使得 x+y=m 。
可以用来合并组合数,降低复杂度。也可以反向使用,方便数据结构维护。
拓展式:
i=0∑m(in)(im)=∑(in)(m−im)=(mn+m)
(rn)(kr)=(kn)(r−kn−k)(5)
(5) **重要!**根据定义求,暴力推阶乘即可。
(rn)(kr)=(n−r)!⋅(r−k)!⋅k!n!=k!⋅(n−k)!n!(n−r)!(r−k)!(n−k)!=(kn)(r−kn−k)
经典的应用:交换求和顺序,化简来降低复杂度:
k=0∑i=0∑f(i)⋅(kn)(ik)=i∑f(i)(in)k∑(k−in−i)=i∑f(i)(in)⋅2n−i
i=0∑n(kl)=(k+1n+1)(6)
(6) **重要!**可以通过组合意义证明。实质上是 (3) 的变形。首先 ∑i=0k−1 是无效的。
考虑从 n+1 个数选择 k+1 个,相当于枚举第一个被选择的数是第几个。
i=0∑k(in)=2⋅i=0∑k(in−1)−(kn)(7)
(7) 同样是一个非常重要的公式,可以根据 (3) 推导出来
i=0∑n(−1)i(in)=0 (n=0)(8)
(8) 反演公式。二项式定理的特殊形式,令 a=1,b=−1 套公式即可。
i=1∑n(in)=2n(9)
(9) 同样可以用二项式定理来证: 2n=(1+1)n=∑(in)
i=0∑ni(in)=n⋅2n−1(10)
(10) 对 (9) 求导可得。
警告⚠:以下过程为大佬讲解但一懂半懂的内容,可能会有错误:
对(in)求生成函数得∑(in)⋅xi则i⋅(in)生成函数的积分为x∑(in)⋅xi后面的部分化简一下为x(1+x)n对上面的东西求导,则为n⋅x⋅(1+x)n−1求和就相当于代入x=1则为n⋅2n−1
或者:
i=0∑ni⋅(in)=i!⋅(n−i)!i⋅n!=(i−1)!⋅(n−i)!n⋅(n−1)!=i=0∑nn⋅(i−1n−1)=n⋅2n−1
i=0∑ni2⋅(in)=n⋅(n+1)⋅2n−2(11)
(11) 在 (10) 的基础上再求一个导。
i=0∑n(in−i)=Fn+1(12)
(12) 组合数和斐波那契数列的联系,证明不会。
不相邻组合
从 n 个数里面选 k 个,任意两个数不相邻的方案数 (kn−k+1) 。
证明:
设 d1,d2,⋯,dk 是一组不相邻组合,令 d1<d2<⋯<dk,c1=d1,c2=d2−1,⋯,ck=dk−k+1 ,易知 c1<c2<⋯<ck<n−k+1 。反之亦然。则 d 与 c 构成充要条件。所以选择 d 的方案数和选择 c 的方案数等价。
多重集的组合数
设广义集合 S=n1⋅ai,n2⋅a2,⋯,nk⋅ak 由 n1 个 a1 ,n2 个 a2 ,⋯ , nk 个 ak 构成。则从 S 里选 r 个数的方案数常表示为:
r1+r2+⋯+rk=r∑(r1,r2,⋯,rkn)
具体情况有两种:
-
r≤mini=1kni ,方案数为 (k−1r+k−1) 。
证明用隔板法即可。考虑这个东西可以理解成 k 个盒子放 r 个球,可空。令 n1′=n1+1,n2′=n2+1,⋯,nk′=nk=1 ,方程就变成了 x1′+x2′+⋯+xk′=r+k ,相当于在 k 个盒子放 r+k 个球,不可空,这样就可以隔板了。方案数为在 r+k−1 个空隙中插入 k−1 个板的方案数,即为 (k−1r+k−1) 。
-
r>mini=1kni ,要用到容斥。可以转换成不定方程非负整数解计数问题。因为这是一个求交集的问题,所以可以转化成求补集的并集。
Ans=S⊆U∑k(−1)∣S∣(k−1k+r−1−∑i∈S(ni+1))
排列
Pnm 代表从 n 个数中选出 m 个元素组成排列(排列是有序的)。
Pnm=(n−m)!n!
圆排列
圆排列就是增加了循环同构的性质,即 1 2 3
和 2 3 1
是一样的。结论 Pnm′=mPnm ,即 pnm=(n−m)!mn!
全错位排列
满足 ∀i∈[1,n],pi=i 的排列叫做全错位排列。
Pn=⎩⎨⎧01(n−1)(Pn−1+Pn−2)n=1n=2n≥3
证明:增量法。
设已经排好了 n−1 个数,现在要加入第 n 个数,能对当前排列数造成贡献的有两类情况。
-
前面全错位,这个时候和前面任意一项交换即可。共有 n−1 种转移方法。
-
前面有一项 x 没有错位,这个时候相当于有 n−2 项满足条件,第 n 项必须和 x 交换。x 一共有 n−1 种情况,每种情况只有 1 种转移方法。
综上所述 Pn=(n−1)(Pn−1+Pn−2)
错位排列
P(n,m)=(n−m)P(n−1,m)+mP(n−1,m−1)
证明和上面类似
多重集的排列数
设广义集合 S=n1⋅ai,n2⋅a2,⋯,nk⋅ak 由 n1 个 a1 ,n2 个 a2 ,⋯ , nk 个 ak 构成。则它的排列数为:
∏i=1kni!n!
类似容斥?把重复的地方扣掉了。
二项式定理
(a+b)=k=0∑nCnkakbn−k
证明:
考虑数学归纳法:
-
当 n=1 时,(a+b)1=Cn0a0b1+Cn1a1b0=a+b 是显然成立的。
-
假设当 n=k 时成立,那么当 n=k+1 时:
(a+b)(a+b)k=(a+b)i=0∑k(ik)aibk−i=i=0∑k(ik)ai+1bk−i+i=0∑k(ik)aibk−i+1=i=1∑k+1(i−1k)aibk−i+1+i=0∑k(ik)aibk−i+1=i=0∑k+1(ik+1)aibk+1−i
证毕。
多项式形式:
(x1+x2+⋯+xk)n=n1+n2+⋯+nk=n∑(n1,n2,⋯,nkn)x1n1x2n2⋯xknk
Lucas 定理
Cnmmodp=Cn/pm/p×Cn modpm modpmodp
一般用来化简项数过高的组合数。
线性求组合数
求组合数可以用 (3) 来进行 n2 递推,但是复杂度不够优秀,所以需要线性求阶乘以及阶乘逆元用定义式来求组合数。
代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| long long jc[Maxn], jc_inv[Maxn], inv[Maxn], P;
void init (long long n) { jc[0] = jc[1] = 1, jc_inv[0] = jc_inv[1] = 1, inv[1] = 1; for (long long i = 2; i <= n; ++i) { jc[i] = jc[i - 1] * i % P; inv[i] = (P - P / i) * inv[P % i] % P; jc_inv[i] = jc_inv[i - 1] * inv[i] % P; } }
long long C (long long n, long long m) { if (n < m) return 0; return jc[n] * jc_inv[m] % P * jc_inv[n - m] % P; }
long long Lucas (long long n, long long m) { if (m == 0) return 1; return C(n % P, m % P) * Lucas (n / P, m / P) % P; }
|
本文作者:CloudySky
写作时间: 2022-01-20
最后更新时间: 2022-01-20
遵循协议: BY-NC-SA