组合数学(未完结)

组合数学

组合数学应该是 OI 中数学板块里内容最多,最重要的一部分了吧。感觉组合数学也是最有意思的。相信可以总结的点一定很多(确信)。希望我的总结不要又臭又长

计数原理

加法原理

若完成一件事的方法有 nn 类,其中第 ii 个步骤包括 aia_i 种不同的方法,且这些方法互不重合,则完成这件事共有 a1+a2++ana_1+a_2+\cdots+a_n 种不同的方法。

乘法原理

若完成一件事需要 nn 个步骤,其中第 ii 个步骤有 aia_i 种不同的完成方法,且这些步骤互不干扰,则完成这件事共有 a1×a2××ana_1 \times a_2 \times \cdots \times a_n 种不同的方法。

排列组合

排列数

nn 个不同元素中依次取出 mm 个元素排成一列,产生的不同排列的数量为:

Anm=n!(nm)!=n×(n1)××(nm+1)\mathrm A_n^m=\frac {n!}{(n-m)!}=n\times (n-1) \times \cdots \times (n-m+1)

组合数

nn 个不同元素中取出 mm 个组成一个集合(不考虑顺序),产生的不同集合数量为:

Cnm=n!m!(nm)!=n×(n1)×(n2)××(nm+1)m×(m1)××2×1\mathrm C_n^m=\frac {n!}{m!(n-m)!}=\frac {n\times (n-1) \times (n-2)\times \cdots \times (n-m+1)}{m \times (m-1) \times \cdots \times 2 \times 1}

基本性质

  1. Cnm=Cnnm\mathrm C_n^m=\mathrm C_n^{n-m}

    展开组合数公式即可。

  2. Cnm=Cn1m+Cn1m1\mathrm C_n^m=\mathrm C_{n-1}^m+\mathrm C_{n-1}^{m-1}

    证明:

    nn 个元素中取 mm 个元素有两类方法:取 nn 号元素和不取 nn 号元素。

    若取 nn 号元素,则需要在剩下 n1n-1 个元素中取 m1m-1 个,即 Cn1m1\mathrm C_{n-1}^{m-1} 种;

    若不取 nn 号元素,则需要在剩下 n1n-1 个元素中取 mm 个,即 Cn1m\mathrm C_{n-1}^m 种。

    然后加法原理即可。

    证毕。

    这条性质同样也可以看做是杨辉三角

  3. Cn0+Cn1+Cn2++Cnn=2n\mathrm C_n^0+\mathrm C_n^1+\mathrm C_n^2+\cdots+\mathrm C_n^n=2^n

    证明:

    nn 个不同元素中取出若干个元素组成一个集合,有 n+1n+1 类方法,分别是取出 0,1,2,,n0,1,2,\cdots,n 个。由加法原理可知,共有 Cn0+Cn1+Cn2++Cnn\mathrm C_n^0+\mathrm C_n^1+\mathrm C_n^2+\cdots+\mathrm C_n^n 种方法。

    也相当于是 nn 个元素中每个元素都可以取或者不去,方案数为 2n2^n

    二者相等。

    证毕。

二项式定理

(a+b)n=k=0nCnkakbnk(a+b)^n=\sum \limits_{k=0}^n \mathrm C_n^k a^k b^{n-k}

证明:

数学归纳法。

n=1n=1 时,(a+b)1=Cn0a0b1+Cn1a1b0=a+b(a+b)^1=\mathrm C_n^0a^0b^1+C_n^1a^1b^0=a+b 成立。

假设当 n=mn=m 时命题成立,当 n=m+1n=m+1 时:

(a+b)m+1=(a+b)(a+b)m=(a+b)k=0mCmkakbmk=k=0mCmkak+1bmk+k=0mCmkakbmk+1=k=1m+1Cmk1akbmk+1+k=0mCmkakbmk+1=k=0m+1(Cmk1+Cmk)akbmk+1=k=0m+1Cm+1kakbm+1k\begin{aligned}(a+b)^{m+1} & =(a+b)(a+b)^m\\&=(a+b)\sum \limits_{k=0}^m \mathrm C_m^k a^k b^{m-k}\\&=\sum \limits_{k=0}^m \mathrm C_m^k a^{k+1}b^{m-k}+\sum \limits_{k=0}^m \mathrm C_m^k a^k b^{m-k+1}\\&=\sum \limits_{k=1}^{m+1}\mathrm C_m^{k-1} a^k b^{m-k+1}+\sum \limits_{k=0}^m \mathrm C_m^k a^k b^{m-k+1}\\&=\sum \limits_{k=0}^{m+1}(\mathrm C_m^{k-1}+\mathrm C_m^k)a^k b^{m-k+1}\\&=\sum \limits_{k=0}^{m+1} C_{m+1}^k a^k b^{m+1-k}\end{aligned}

证毕。

组合数求和

  • 对角线求和Cnm+Cn+1m+1++Cn+km+k=Cn+k+1m+k+Cnm1\mathrm C_n^m+\mathrm C_{n+1}^{m+1}+\cdots+\mathrm C_{n+k}^{m+k}=\mathrm C_{n+k+1}^{m+k}+\mathrm C_n^{m-1}

  • 直线求和Cnm+Cn+1m++Cn+km=Cn+k+1m+1Cnm+1\mathrm C_n^m+\mathrm C_{n+1}^m+\cdots+\mathrm C_{n+k}^m=\mathrm C_{n+k+1}^{m+1}-\mathrm C_n^{m+1}

组合数求法

  1. 递推法

    根据基本性质 2,通过杨辉三角递推求组合数。

    时间复杂度:O(n2)O(n^2)

    此方法主要适用于预处理。

    代码实现:

    C[0][0]=1;//upd on 2022.7.18:一般来说不会用到这个,但是我在某场模拟赛补题中因为这个 WA 75pts 了。
    for (int i=1;i<=n;i++)
    for (int j=0;j<=i;j++)
    {
        if (i==1 || j==0) C[i][j]=1;
        else C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
    }
    
  2. 乘法逆元

    此方法主要用于结果要求模大素数时。比如我们要求 Cnm modp\mathrm C_n^m \bmod p

    因为 Cnm=n!m!(nm)!\mathrm C_n^m=\frac {n!}{m!(n-m)!},所以我们可以预处理出来 n! modpn! \bmod p 以及 m! modpm! \bmod p(nm)! modp(n-m)! \bmod p 的逆元,然后三者相乘即为答案。

    时间复杂度:O(n)O(n)

    代码实现:

    void init()//预处理
    {
        jc[0]=jc[1]=inv[0]=inv[1]=in[1]=in[0]=1;
        for(int i=2;i<=n;i++)
        {
            jc[i]=jc[i-1]*i%mod;//阶乘
            inv[i]=(mod-mod/i)*inv[mod%i]%mod;//inv[] 是逆元。
            in[i]=in[i-1]*inv[i]%mod;//in[] 表示阶乘逆元。
        }
    }
    
    int C(int n,int m){return jc[n]*in[m]%mod*in[n-m]%mod;}
    
  3. 质因数分解

    因为 Cnm=n!m!(nm)!\mathrm C_n^m=\frac {n!}{m!(n-m)!},所以可以对分子,分母快速分解质因数,在数组中保存各项质因子的质数。然后把分子,分母各个质因子的指数对应相减(把分母消去),最后把剩余质因子乘起来即可。

    时间复杂度:O(nlogn)O(n \log n)

Lucas 定理

pp 是质数,则对于任意整数 1mn1 \le m \le n,有:

CnmCn modpm modp×Cn/pm/p(modp)C_n^m \equiv C_{n \bmod p}^{m \bmod p} \times C_{n/p}^{m/p} \pmod p

也就是把 nnmm 表示成 pp 进制数,对 pp 进制下的每一位分别计算组合数,最后再乘起来。

本来是不打算写证明的,因为这个证明也不需要掌握,但是我感觉它非常有意思,所以就把它写在这里吧。

证明:

咕咕咕……(组合数学完全整理完之前一定过来补上!)

证毕。

代码实现:

int lucas(int n,int m,int p)
{
    if(m==0)return 1;
    return (C(n%p,m%p,p)*lucas(n/p,m/p,p))%p;
}

可重集的排列数

可重集,指的是包含重复元素的广义集合。

nn 种字母,每种字母 aia_i 个,有 n!(ai!)\frac {n!}{\prod(a_i!)} 种不同的排列。

可重集的组合数

S={n1×a1,n2×a2,,nk×ak}S=\{n_1 \times a_1,n_2 \times a_2,\cdots,n_k \times a_k\} 是由 n1n_1a1a_1n2n_2a2a_2,…,nkn_kaka_k 组成的可重集。

设整数 rni(i[1,k])r \le n_i(\forall i \in [1,k])。从 SS 中取出 rr 个元素组成一个可重集(不考虑元素的顺序),产生的不同可重集的数量为 Ck+r1k1\mathrm C_{k+r-1}^{k-1}

证明:

原问题等价于求下列集合的数量:{x1×a1,x2×a2,,xk×ak}\{x_1 \times a_1,x_2\times a_2,\cdots,x_k\times a_k\},其中 i=1kxi=r(xini)\sum \limits_{i=1}^k x_i=r(x_i\le n_i)

原问题等价于 rr 个 0,k1k-1 个 1 构成的全排列数——k1k-1 个 1 把 rr 个 0 分成 kk 组,每组的 0 的数量对应的是 xix_i

也可以看做总共有 k+r1k+r-1 个元素,然后我们要选择其中 k1k-1 个作为隔板,求总的方案数。

而可重集 {r0,(k1)1}\{r \cdot 0,(k-1) \cdot 1\} 的全排列个数为:

(r+k1)!r!(k1)!=Ck+r1r=Ck+r1k1\frac {(r+k-1)!}{r!(k-1)!}=\mathrm C_{k+r-1}^r=\mathrm C_{k+r-1}^{k-1}

证毕。

不相邻的排列

1n1-nnn 个自然数中选 kk 个,这 kk 个数中任何两个数都不相邻的组合有 Cnk+1k\mathrm C_{n-k+1}^k 个。

证明:

插空法。利用逆向思维,先从 nk+1n-k+1 个数中任选 kk 个数,共 Cnk+1k\mathrm C_{n-k+1}^k 种方案。然后再把 k1k-1 个数当做空位插入到 kk 个数的 k1k-1 个空中,即为 nn 个自然数。

证毕。

错位排列

1n1-nnn 个自然数生成全排列,其中第 i(1in)i(\forall 1\le i \le n) 位不能为 ii 的方案数被称为错位排列,简称错排,记为 DnD_n

我们分两步考虑递推关系:

  • 第一步,考虑第 nn 个元素,把它放在在某一个位置,比如位置 kk,一共有 n1n-1 种放法;

  • 第二步,考虑第 kk 个元素,这时有两种情况:

    1. 把它放到位置 nn,那么对于除 nn 以外的 n1n-1 个元素,由于第 kk 个元素放到了位置 nn,所以考虑剩下 n2n-2个元素的错排即可,有 Dn2D_{n-2} 种放法;

    2. kk 个元素不放到位置 nn,这时对于这 n1n-1 个元素的错排,有 Dn1D_{n-1} 种放法。

根据乘法原理加法原理可知:

Dn=(n1)(Dn1+Dn2)D_n=(n-1)(D_{n-1}+D_{n-2})

另外:

Dn=AnnAnn1+Ann2Ann3++(1)nAn0=i=0n(1)i×AnniD_n=A_n^n-A_n^{n-1}+A_n^{n-2}-A_n^{n-3}+\cdots+(-1)^n A_n^0=\sum \limits_{i=0}^n (-1)^i\times A_n^{n-i}

这一点是根据容斥原理推出来的。

也就是说,nn 的错排等于 nn 的全排列,减去至少有一个数不是错排的方案数,加上至少有两个数不是错排的方案数,减去至少有三个数不是错排的方案数……

注意,容斥原理是总方案数-不合法方案数,这里的“不是错排”就是“错排”的反义,所以不是错排的方案数就是不合法方案数。

错位排列前几项:0,1,2,9,44,2650,1,2,9,44,265

圆排列

nn 个人全部来围成一圈,所有的排列数记为 QnnQ_n^n

考虑其中已经排好的一圈,从不同位置断开,变成不同的队列。所以有:

Qnn×n=AnnQ_n^n \times n=A_n^n

那么部分圆排列的方案数(即 nn 个人中挑出 rr 个人围成一圈)为:

Qnr=Anrr=n!r×(nr)!Q_n^r=\frac {A_n^r} {r}=\frac {n!}{r \times (n-r)!}

另外,将 nn 个不同的数构成 mm 个圆排列的数目被称为第二类斯特林数,后面会专门说到斯特林数,这里不再赘述。

放球问题

最全面的放球问题请参考放球问题 学习笔记 - ACodinghusky - 博客园,这里只讨论最常见的 8 种情况。

在考虑这个问题之前,我们先解释一个问题:球同球异盒同盒异到底有什么区别?

说实话,我其实刚开始一直是糊涂的,知道看到 dbxxx 的博客里面的一段话才理解:

球盒区别解释

假设n=3,m=2,对球编号 1,2,3:

为方便,规定类似于如下的表示:{1, 2}, {3} 表示第一个盒子中有1,2两个球,第二个盒子中有3一个球

而且无论十六种问题中哪一种,对于单个盒子而言,即使球有区别,盒子内部球的顺序永远只算一种情况。也就是说 {1, 2}, {3} 和 {2, 1}, {3} 只能算作一种情况(无论 16 种问题的哪一个。)

如果球有区别,盒也有区别,那么除了上一句说的情况外,其他所有的都各自算各自的情况。比如:

{1, 2}, {3}{3}, {1, 2}{1, 3}, {2} 这三种情况每一种都是不同的。

如果球无区别,意味着将来自两个盒子的两个球进行交换是算作一种情况的。比如:

{1, 2}, {3} 和 {1, 3}, {2} 是一种情况。

如果盒无区别,意味着将任意两个盒子调换位置是算作一种情况的。比如:

{1, 2}, {3} 和 {3}, {1, 2} 是一种情况。

那么如果球和盒都没有区别……

{1, 2}, {3}{3}, {1, 2}{1, 3}, {2}{2, 3}, {1}{2}, {1, 3} 等都是一种情况。

在球和盒都没有区别的模型下,还可以创造新的情况吗?

{}, {1, 2, 3},可以将一个盒子清空,这样就可以创造另一种情况了。同理,{1, 2, 3}, {} 和 {}, {1, 2, 3} 是一种情况,因为盒子没有区别。

在球和盒都没有区别的模型下,必须有空的集合才能有别的情况吗?当然不是。不妨考虑扩展到 4 个球。那么:

{}, {1, 2, 3, 4}{1}, {2, 3, 4}{1, 2}, {3, 4} 就是三种情况。

这里必须 %%% dbxxx,真的是把这个问题总结的非常全面详细。大家有兴趣可以去看看上面我放的他的博客。

假设有 nn 个球和 mm 个盒子,那么有如下 4 类 8 种情况:

  1. 球异,非空

    • 盒同

      实际上就是第二类斯特林数,因此答案是 S(n,m)S(n,m)

      第二类斯特林数的求法下面会提到,这里不做赘述。

    • 盒异

      就相当于是计算出上述盒同的所有情况后给盒子编号,所以需乘上盒子的全排列。

      所以答案是 m!×S(n,m)m!\times S(n,m)

  2. 球异,可空

    • 盒异

      每个球都有 mm 种放法,那么 nn 个球就是 nnmm 相乘,也就是 mnm^n 种放法。

    • 盒同

      和 1 中的第一种情况的区别在于,盒子可以空放了。

      那么枚举空盒个数累计到第二类斯特林数即可。因此,答案为 k=1mS(n,k)\sum \limits_{k=1}^m S(n,k)

  3. 球同,非空

    • 盒异

      隔板法。题目相当于把 nn 个球分成 mm 段,那么需要 m1m-1 个隔板。

      nn 个球之间有 n1n-1 个缝隙。所以问题就转化为从 n1n-1 个缝隙中找到 m1m-1 个插进去。

      所以答案为 Cn1m1\mathrm C_{n-1}^{m-1}

    • 盒同

      请先移步到 4 第二种情况。在那一种情况基础之上,当遇到非空,我们强制给每个盒子一个球转化为可空,方案数就为 dpnmmdp_{n-m}{m}

  4. 球同,可空

    • 盒异

      同样和 3 中的第一种情况的区别在于,盒子可以空放了。

      我们运用化归思想,把可空问题转化为非空问题。

      先构造 n+mn+mmm 盒和 3 中的第一种情况一样的问题。

      然后在所有方案中,我们给每个盒子里面去掉一个球,这样球的总数还是 nn 个,方案也就转化成了可空的问题。

      也就是说可空的 nnmm 盒问题,可以转化为不可空的 n+mn+mmm 盒问题。

      那么最后答案就是 Cm+n1m1\mathrm C_{m+n-1}^{m-1}

      怎么样?是不是很巧妙?

    • 盒同

      实际上要求的是长度为 mm 的有序数列个数,数列的元素和为 nn
      dpn,mdp_{n,m} 为划分方案数,有

      dp0,k=dpk,1=1dpi,j=dpij,j+dpi,j1dp_{0,k} = dp_{k,1} = 1\\dp_{i,j} = dp_{i − j,j} + dp_{i,j − 1}

      状态转移方程解释:考虑 jj 个盒子中是否有空盒

      1. 有空盒:新增一个空盒,贡献 dpi,j1dp_{i,j-1}

      2. 无空盒:向每个盒子放入一个球使其非空,贡献 dpij,jdp_{i-j,j}

两类特殊的数

卡特兰数

给定 nn 个 0 和 nn 个 1,它们按照某种顺序排成长度为 2n2n 的序列, 满足任意前缀中 0
的个数都不少于 1 的个数的序列的数量为:

Catn=C2nnn+1=C2nnC2nn1Cat_n=\frac {\mathrm C_{2n}^n}{n+1}=\mathrm C_{2n}^n-\mathrm C_{2n}^{n-1}

证明:

nn 个 0 和 nn 个 1 随意排成一个长度为 2n2n 的序列 SS,若 ss 不满足任意前缀中 0 的个数都不少于 1 的个数,那么一定存在一个最小的位置 2p+1[1,2n]2p+1\in [1,2n],使得 S[12p+1]S[1 \thicksim 2p+1] 中有 pp 个 0,p+1p+1 个 1。

所以此时,S[2p+22n]S[2p+2 \thicksim 2n] 中含有 np1n-p-1 个 1 和 npn-p 个 0,,所以把 S[2p+22n]S[2p+2 \thicksim 2n] 中的所有数字取反以后,包含 np1n-p-1 个 0 和 npn-p 个 1。加上前 2p+12p+1 个,于是我们得到了由 n1n-1 个 0 和 n+1n+1 个 1 排成的序列。

同理,令 n1n-1 个 0 和 n+1n+1 个 1 随意排成一个长度为 2n2n 的序列 SS',也必定存在一个最小的位置 2p+12p'+1,使得 S[12p+1]S'[1 \thicksim 2p'+1] 中有 pp' 个 0,p+1p'+1 个 1。把 SS' 后面剩下的一半取反,就得到了由 n+1n+1 个 0 和 nn 个 1 排成的,存在一个前缀 0 比 1 多的序列。

因此,以下两种序列构成了一个双射

  1. nn 个 0 和 nn 个 1 排成的,存在一个前缀 0 比 1 多的序列;

  2. n1n-1 个 0 和 n+1n+1 个 1 排成的序列。

根据组合数的定义,后者显然有 C2nn1\mathrm C_{2n}^{n-1} 个。

综上,由 nn 个 0 和 nn 个 1 排成的,任意前缀中 0 的个数都不少于 1 的个数的序列的数量为:

Catn=C2nnC2nn1=C2nnn+1Cat_n=\mathrm C_{2n}^n-\mathrm C_{2n}^{n-1}=\frac {\mathrm C_{2n}^n}{n+1}

证毕。

推论

  1. nn 个左括号和 nn 个右括号组成的合法括号序列的数量为 CatnCat_n

  2. 1n1-nnn 个自然数依次进栈,形成的合法的出栈序列的数量为 CatnCat_n

  3. nn 个节点构成的不同二叉树的数量为 CatnCat_n

  4. n+2n+2 边形过顶点切分成 nn 个三角形的不同方案数;

  5. 在平面直角坐标系上,每一步只能向上或向右走,从 (0,0)(0,0) 走到 (n,n)(n,n) 并且除两个端点之外不接触直线 y=xy=x 的路线数量是 2Catn12Cat_{n-1}

  6. 给定 nn 个 0 和 1,其中 mm 个为 0,其余是 1 的 Catalan 数为:

    CnmCnm1\mathrm C_n^m-\mathrm C_n^{m-1}

    或者给定 n+mn+m 个 0 和 1,其中 mm 个为 0,nn 个为 1 的 Catalan 数为:

    Cn+mmCn+mm1\mathrm C_{n+m}^m-\mathrm C_{n+m}^{m-1}

    物理意义:在平面直角坐标系上,每一步只能向上或向右走,从 (0,0)(0,0) 走到 (n,m)(n,m) 并且除两个端点之外不接触直线 y=xy=x 的路线数量。

斯特林数


写在后面

post on 2022.4.19

组合数学这个我保证在完全结束这一板块的学习之前,就把所有该总结的都总结完。

一是这个版块的确是太重要了,另外咕咕咕并非一个好的习惯。

现在才有三千多字,后面可能会成倍成倍的往上增长(不是)。

感觉组合数学真的非常有意思,而且让人回味无穷(确信),但是这仍然改变不了我菜的事实

说起来多多少少和组合数学有点渊源,毕竟,我在洛谷上发的第一篇题解就是组合数学,我 AC 的第一道黑题就是组合数学,我在洛谷上提交次数最多的题目也还是道组合数学。

艾教说,组合数学学好了整个 dp 就会串起来,就会变得非常强。

所以我会尽力把组合数学这块学好的。

To be continued……

posted @   向日葵Reta  阅读(221)  评论(3编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示