组合计数
加法原理
若完成一件事的方法有 n 类,其中第 i 类方法包括 ai 种不同的方法,且这些方法互不重合,则完成这件事共有 a1+a2+…+an 种不同的方法
乘法原理
若完成一件事需要 n 个步骤,其中第 i 个步骤有 ai 种不同的完成方法,且这些步骤互不干扰,则完成这件事共有 a1\*a2\*…\*an 种不同的方法
排列数
从 n 个不同的元素中依次取出 m 个元素排成一列,产生的不同排列的数量为:
Pmn=n!(n−m)!=n\*(n−1)\*…\*(n−m+1)
组合数
从 n 个不同的元素中取出 m 个元素组成一个集合(不考虑顺序),产生的不同集合的数量为:
Cmn=n!m!(n−m)!=n\*(n−1)\*…(n−m+1)m\*(m−1)\*…\*2\*1
性质
- Cmn=Cn−mn
- Cmn=Cmn−1+Cm−1n−1
- C0n+C1n+C2n+…+Cnn=2n
证明:
由组合数的定义,对于从 n 个不同的元素中取出 m 个组成的每个集合,剩余未取出的元素也构成一个集合,两个集合一一对应,所以性质 1 成立。
从 n 个不同元素中取出 m 个组成一个集合有两类方法:取 n 号元素,不取 n 号元素。若取 n 号元素,则应在剩余 n−1 个元素中选出 m−1 个,有 Cm−1n−1 种取法。若不取 n 号元素,则应在剩余 n−1 个元素中选出 m 个, 有 Cmn−1 种取法。根据加法原理,性质 2 成立。
从 n 个不同元素中取出若干个元素组成一个集合,有 n+1 类方法,分别是取出 0,1,2,…,n 个。根据加法原理,共有 C0n+C1n+C2n+…+Cnn 种方法。从另一个方面去考虑,n 个元素每个元素可以取或不取,总方法数为 2n,二者相等,故性质 3 成立。
证毕。
组合数的求法
根据性质 2,用递推法可求出 0≤y<x≤n 的所有组合数 Cyx,复杂度为 O(n2)
组合数的结果一般较大,若题目求出 Cmn 对一个数 p 取模后的值,并且 1∼n 都存在模数 p 的逆元,则可以先计算分子 n! mod p,再计算分母 m!(n−m)! mod p 的逆元,乘起来得到 Cmn mod p,复杂度为 O(n)。
若计算阶乘的过程中,把 0≤k≤n 的每个 k! mod p 及其逆元分别保存在两个数组 jc 和 jcinv 中,则可以在 O(nlogn) 的预处理后,以 O(1) 的时间回答 0≤y<x≤n 的所有组合数 Cyx mod p=jc[x]\*jcinv[y]\*jcinv[x−y] mod p。
若题目要求我们对 Cmn 进行高精度运算,为避免除法,可用 “阶乘分解” 的做法,把分子、分母快速分解质因数,在数组中保存各项质因子的指数,然后把分子、分母各个质因子的指数对应相减(把分母消去),最后把剩余质因子乘起来,时间复杂度为 O(nlogn)
Lucas 定理
若 p 是质数,则对于任意整数 1≤m<n,有:
Cmn=Cm mod pn mod p\*Cm/pn/p (mod p)
也就是把 n 和 m 表示成 p 进制数,对 p 进制下的每一位分别计算组合数,最近再乘起来。证明需要用到生成函数的知识,也可以看 y 总的算法基础课,有机会再补叭。
二项式定理
(a+b)n=n∑k=0Cknakbn−k
证明:
数学归纳法。当 n=1 时,(a+b)1=C0na0b1+C1na1b0=a+b 成立。
假设当 n=m 时命题成立,当 n=m+1 时:
(a+b)m+1=(a+b)(a+bm)=(a+b)m∑k=0Ckmakbm−k
=m∑k=0Ckmak+1bm−k+m∑k=0Ckmak+1bm−k+1=m+1∑k=1Ck−1makbm−k+1+m∑k=0Ckmakbm−k+1
=m+1∑k=0(Ck−1m+Ckm)akbm−k+1=m+1∑k=0Ckm+1akbm+1−k
证毕。
容斥原理
设 S1,S2,…,Sn 为有限集合,|S| 表示集合 S 的大小,则:
|n⋃i=1Si|=n∑i=1|Si|−∑1≤i<j≤n|Si∩§j|+∑1≤i<j<k≤n|Si∩Sj∩Sk|+…+(−1)n+1|S1∩…∩Sn|
可以查找文氏图来帮助理解公式。
多重集的排列数
多重集是指包含重复元素的广义集合。设 S={n1⋅a1,n2⋅a2,…,nk⋅ak} 是由 n1 个 a1,n2 个 a2 … nk 个 ak 组成的多重集,记 n=n1+…+nk。S 的全排列个数为:
n!n1!n2!…nk!
多重集的组合数
设 S={n1⋅a1,n2⋅a2,…,nk⋅ak 是由 n1 个 a1,n2 个 a2 … nk 个 ak 组成的多重集,设整数 r≤ni (∀i∈[1,k])。从 S 中取出 r 个元素组成一个多重集(不考虑元素的顺序),产生的不同多重集的数量为:
Ck−1k+r−1
证明:
原问题等价于统计下列集合的数量:{x1⋅a1,x2⋅a2,…,xk⋅ak,其中 ∑ki=1xi=r 并且 xi≤ni。因为 r≤ni,必定有 xi≤ni,所以只需考虑 ∑ki=1xi=r 这一个条件。
故原问题等价于 r 个 0,k−1 个 1 构成的全排列数———k−1 个 1 把 r 个 0 分成 k 组,每组的 0 的数量对应 xi,而多重集 {r⋅0,(k−1)⋅1} 的全排列数为:
(r+k−1)!r!(k−1)!=Crk+r−1=Ck−1k+r−1
证毕。
对于更为一般的 r 的情况,则需进一步分析。
设 S={n1⋅a1,n2⋅a2,…,nk⋅ak} 是由 n1 个 a1,n2 个 a2,…,nk 个 ak 组成的多重集。设 n=∑ki=1ni,对于任意整数 r≤n,从 S 中取出 r 个元素组成一个多重集(不考虑顺序),产生的不同多重集的数量为:
Ck−1k+r−1−k∑i=1Ck−1k+r−ni−2+∑1≤i<j≤kCk−1k+r−ni−nj−3−…+(−1)kCk−1k+r−∑ki=1ni−(k+1)
证明:
不考虑 ni 的限制,从 S 中任选 r 个元素,相当于从多重集 {∞⋅a1,∞⋅a2,…,∞⋅ak} 中取出 r 个元素。根据上面的证明,可知方法数为 Ck−1k+r−1
设 Si (1≤i≤k) 表示至少包含 ni+1 个 ai 的多重集,我们先从 S 中取出 ni+1 个 ai,然后再任选 r−ni−1 个元素,即可构成 Si。与上面同理,可以构成的不同 Si 的数量为 Ck−1k+r−ni−2
进一步分析,先从 S 中取出 ni+1 个 ai 和 nj+1 个 aj,然后再任选 r−ni−nj−2 个元素,即可构成 Si∩Sj,方法数为:
Ck−1k+r−ni−nj−3
根据容斥原理,至少有一种 ai 选取的数量超过 ni 限制的多重集共有:
|k⋃i=1Si|=k∑i=1Ck−1k+r−ni−2−∑1≤i<j≤kCk−1k+r−ni−nj−3+…+(−1)k−1Ck+1k+r−∑ki=1ni−(k+1)
故满足所有限制的合法多重集共有 Ck−1k+r−1−|∪ki=1Si| 个,两式相减即得原命题。
证毕。
Mobius 函数
设正整数 N 按照算术基本定理分解质因数为 N=pc11pc22…pmcm,定义函数
μ(N)={0∃i∈[1,m],ci>11m≡0 (mod 2),∀i∈[1,m],ci=1−1m≡1 (mod 2),∀i∈[1,m],ci=1
称 μ(N) 为 Mobius 函数(莫比乌斯函数)
直白点说,当 N 包含相等的质因子时,μ(N)=0。当 N 的所有质因子各不相等时,若 N 有偶数个质因子,μ(N)=1,若 N 有奇数个质因子,μ(N)=−1
若只求一项 Mobius 函数,则分解质因数就能计算。若求 1∼N 的每一项 Mobius 函数,可以利用线性筛法计算,实现代码如下:
void get_primes(int n) //线性筛法求莫比乌斯函数
{
mobius[1] = 1; //1 有 0 个质因子,是偶数个质因子
for(int i = 2; i <= n; i++)
{
if(!st[i])
{
primes[cnt++] = i;
mobius[i] = -1; //质数的质因子只有一个,是奇数
}
for(int j = 0; primes[j] <= n / i; j++)
{
st[primes[j] * i] = true;
if(i % primes[j] == 0)
{
//到这说明 primes[j] * i 中至少有 2 个 primes[j],因此质因子数量 > 1
mobius[primes[j] * i] = 0;
break;
}
//到这说明 i 中没有质因子 primes[j],因此 primes[j] * i 的质因子个数就是 i 的质因子个数 + 1
mobius[primes[j] * i] = mobius[i] * -1;
}
}
}
Mobius 函数的作用
假设要求与 N 互质的个数。
可以用容斥原理来求,假设 Sp 为 1∼N 中 p 的个数
那么与 N 互质的个数:N−S2−S3…+S2,3+S2,5+…−S2,3,5−…
可以发现 Mobius(2)=−1,Mobius(3)=−1,Mobius(6)=1,Mobius(10)=1,容斥原理中每一项 Si 的系数就是 Mobius(i)
Catalan 数列
给定 n 个 0 和 n 个 1,它们按照某种顺序拍成长度为 2n 的序列,满足任意前缀中 0 的个数都不少于 1 的个数的序列数量为:
Catn=Cn2nn+1
证明:
令 n 个 0 和 n 个 1 随意排成一个长度为 2n 的序列 S,若 S 不满足任意前缀中 0 的个数都不少于 1 的个数,则存在一个最小的位置 2p+1∈[1,2n],使得 S[1∼2p+1] 中有 p 个 0、p+1 个 1。而把 S[2p+2∼2n] 中所有数字取反后,包含 n−p−1 个 0 和 n−p 个 1。于是我们得到了由 n−1 个 0 和 n+1 个 1 排成的序列。
同理,令 n−1 个 0 和 n+1 个 1 随意排成一个长度为 2n 的序列 S′,也必定存在一个最小的位置 2p′+1,使得 S[1∼2p′+1] 中有 p′ 个 0、p′+1 个 1。把 S′[2p′+2∼2n] 中所有数字取反,就得到了由 n 个 0 和 n 个 1 排成的、存在一个前缀 0 比 1 多的序列。
因此,以下两种序列构成一个双射:
- 由 n 个 0 和 n 个 1 排成的、存在一个前缀 0 比 1 多的序列。
- 由 n−1 个 0 和 n+1 个 1 排成的序列。
根据组合数的定义,后者显然有 Cn−12n 个。
综上所述,由 n 个 0 和 n 个 1 排成的,任意前缀中 0 的个数都不少于 1 的个数的序列数量为:
Cn2n−Cn−12n=(2n)!n!n!−(2n)!(n−1)!(n+1)!=Cn2nn+1=Catn
证毕。
推论
以下问题都与 Catalan 数有关。
- n 个左括号和 n 个右括号组成的合法括号序列的数量为 Catn。
- 1,2,…,n 经过一个栈,形成的合法出栈序列序列的数量为 Catn。
- n 个节点构成的不同二叉树的数量为 Catn。
- 在平面直角坐标系上,每一步只能向上或向右走,从 (0,0) 走到 (n,n) 并且除两个端点外不接触直线 y=x 的路线数量为 2Catn−1
求关注(´இωஇ`)