NOI C++ 课程体系 / 数学基础篇 / 第5讲
CSP-J/S · 离散与组合数学 · m6-05

离散数学
与组合计数

从"有多少种方法"到杨辉三角的奥秘——掌握排列组合的核心公式,让计数问题不再靠猜!

6 大模块 2 大计数原理 P/C 核心公式 5 大易错点 12 道分层练习
本讲 · 第 55/56 讲离散与组合数学
模块 01

情景导航

用故事建立直觉,用类比理解抽象概念。

故事帕斯卡与神奇的三角形

1654年,法国数学家布莱兹·帕斯卡(Blaise Pascal)在研究赌博问题时,发现了一个惊人的规律:

      1
     1  1
    1  2  1
   1  3  3  1
  1  4  6  4  1
 1  5  10  10  5  1

这个三角形中,每个数等于它上方两个数之和。而第 n 行第 m 个数,恰好就是组合数 C(n,m)!

这个三角形在中国被称为"杨辉三角"(比帕斯卡早了约400年),它是组合数学最优美的结构之一。

今天,我们用计算机生成它只需几行代码,但理解它背后的计数思想才是竞赛的关键。

💡 为什么组合数学是竞赛必考?

"有多少种方案?""有多少种走法?""满足条件的子集有几个?"——这类计数问题在初赛中几乎每年必考,在复赛中也是DP和数学题的基础。

不懂组合数学,就只能暴力枚举;懂了公式,O(1) 直接出答案。

①生活类比:计数无处不在
👔

穿搭 = 乘法原理

3件上衣 × 4条裤子 = 12种搭配。

→ 分步计数用乘法
🚗

出行 = 加法原理

坐公交3条线 + 地铁2条线 = 5种选择。

→ 分类计数用加法
🏆

颁奖 = 排列

5人中选3人分获金银铜,顺序重要。

→ P(5,3) = 60
🤝

组队 = 组合

5人中选3人参加比赛,不分先后。

→ C(5,3) = 10
②编程定义:本讲知识地图

本讲涵盖大纲中 "离散数学" 与 "组合数学" 的核心计数内容。

📌 本讲核心知识地图

板块核心内容对应大纲
计数原理加法原理、乘法原理加法原理、乘法原理
排列P(n,m) 公式、全排列排列数
组合C(n,m) 公式、性质组合数
杨辉三角递推关系、组合恒等式杨辉三角、二项式定理
Lucas定理大组合数取模(选学)组合数取模
卡特兰数括号序列、二叉树计数特殊数列(拓展)
③核心口诀
🔑 口诀一:两大计数原理

分类用加法,分步用乘法
先判类型再计算,混淆两者全白搭

🔑 口诀二:排列 vs 组合

有序排列P,无序组合C
P比C多除阶乘,顺序无关就选C

🔑 口诀三:杨辉三角

C(n,m) = C(n-1,m-1) + C(n-1,m)
肩上两数相加得,边界全是1

模块 02

知识探究

系统掌握计数原理、排列组合公式、杨辉三角与经典计数模型。

1加法原理与乘法原理 基石
➕ 加法原理(分类计数)
  • 完成一件事有 n 类方法
  • 各类方法互相独立、互不重叠
  • 总方法数 = 各类方法数之和
  • 关键词:"或"、"要么...要么..."
✖️ 乘法原理(分步计数)
  • 完成一件事需 n 步
  • 每步必须依次完成才算成功
  • 总方法数 = 各步方法数之积
  • 关键词:"且"、"先...再..."
⚠️

最容易犯的错:加法和乘法搞混

❌ 错误思维
从A到B有3条路,从B到C有2条路
"3+2=5种走法" ← 这是错的!
必须走完A→B→C才算到达
✅ 正确分析
A→B 和 B→C 是两步,缺一不可
应该用乘法:3 × 2 = 6 种
只有"要么走A→B,要么走A→C"才用加法
🔑 判断口诀

做完这件事了吗?
• 只做其中一类就完成了 → 加法
• 只做一步还没完成 → 乘法

2排列数 P(n, m) 必考

排列:从 n 个不同元素中取出 m 个,按一定顺序排成一列的方法数。

P(n, m) = n! / (n-m)! = n × (n-1) × ... × (n-m+1)
从 n 开始连乘 m 个递减整数

🖐 手推示例:P(5, 3)

1
第1个位置:5种选择
从5个元素中任选1个
2
第2个位置:4种选择
剩下4个元素中选1个
3
第3个位置:3种选择
剩下3个元素中选1个
✓
P(5,3) = 5 × 4 × 3 = 60
乘法原理:三步相乘
特殊情况公式值
全排列P(n,n) = n!P(4,4)=24, P(5,5)=120
取0个P(n,0) = 1空排列只有1种
取1个P(n,1) = n显然
3组合数 C(n, m) 必考

组合:从 n 个不同元素中取出 m 个,不考虑顺序组成一组的方法数。

C(n, m) = P(n,m) / m! = n! / (m! × (n-m)!)
排列数 ÷ 内部排列数 = 去掉顺序

💡 核心直觉:组合 = 排列 ÷ 重复计数。选出m个元素后有 m! 种排法,但它们算同一种组合。

📌 基本性质
  • C(n,0) = C(n,n) = 1
  • C(n,1) = n
  • C(n,m) = C(n, n-m)
  • 对称性:选m个 = 留n-m个
📌 常用恒等式
  • C(n,m)+C(n,m+1)=C(n+1,m+1)
  • ΣC(n,k) = 2ⁿ (k=0..n)
  • k·C(n,k) = n·C(n-1,k-1)
📌 计算技巧
  • C(n,m) = n/m × C(n-1,m-1)
  • 递推避免阶乘溢出
  • C(10,3)=10×9×8/6=120
C++组合数计算(防溢出)
// 方法1:递推法(推荐,O(n²)预处理)
long long C[2001][2001];
void init() {
    for (int i = 0; i <= 2000; i++) {
        C[i][0] = C[i][i] = 1;
        for (int j = 1; j < i; j++)
            C[i][j] = C[i-1][j-1] + C[i-1][j];
    }
}

// 方法2:直接计算(小数据量)
long long comb(int n, int m) {
    if (m > n || m < 0) return 0;
    long long res = 1;
    for (int i = 0; i < m; i++)
        res = res * (n - i) / (i + 1); // 先乘后除,保证整除
    return res;
}
💡 关键细节:res * (n-i) / (i+1) 中,连续 i+1 个整数的乘积一定能被 (i+1) 整除,所以不会丢失精度。
4杨辉三角与递推 核心
C(n, m) = C(n-1, m-1) + C(n-1, m)
每个组合数 = 左肩 + 右肩(杨辉三角递推公式)

💡 组合意义解释:从n个元素中选m个,考虑某个特定元素x:

✅ 选了 x
  • 还需从剩余 n-1 个中选 m-1 个
  • 方法数 = C(n-1, m-1)
❌ 没选 x
  • 需从剩余 n-1 个中选 m 个
  • 方法数 = C(n-1, m)

两类互斥且完备 → C(n,m) = C(n-1,m-1) + C(n-1,m)

🔑 杨辉三角的性质

① 第 n 行所有数之和 = 2ⁿ
② 左右对称:C(n,m) = C(n,n-m)
③ 斜线之和 = 斐波那契数列
④ 第 n 行第 m 个数 = C(n,m)(从0开始编号)

5Lucas 定理(选学) 进阶

当 n, m 很大(如 10¹⁸)但模数 p 较小(如 ≤10⁵ 的质数)时,无法直接计算 C(n,m) mod p。

C(n, m) mod p = ∏ C(nᵢ, mᵢ) mod p
其中 nᵢ, mᵢ 分别是 n, m 在 p 进制下的各位数字
C++Lucas定理模板
long long lucas(long long n, long long m, int p) {
    if (m == 0) return 1;
    return comb(n % p, m % p, p) 
         * lucas(n / p, m / p, p) % p;
}
💡 CSP-J 不要求,CSP-S/NOIP 偶尔出现。理解思路即可,不必死记代码。
6卡特兰数入门 拓展

卡特兰数是一组在组合计数中频繁出现的特殊数列。

Cat(n) = C(2n, n) / (n+1) = C(2n,n) - C(2n,n+1)
前几项:1, 1, 2, 5, 14, 42, 132, 429...
经典模型描述答案
合法括号序列n对括号的合法排列数Cat(n)
栈的出栈序列n个元素依次入栈,合法出栈序列数Cat(n)
二叉树形态n个节点的不同二叉树形态数Cat(n)
网格路径n×n网格从左下到右上不越过对角线Cat(n)
凸多边形三角剖分n+2边形用不相交对角线分成三角形Cat(n)
🔑 识别卡特兰数的信号

看到"合法括号""栈序列""二叉树形态""不越对角线" → 大概率是卡特兰数!
Cat(n) = C(2n,n)/(n+1),记住前5项:1,1,2,5,14

模块 03

实践应用

通过典型例题,巩固排列组合的计算与建模能力。

题1排列组合计算

题目:从7名同学中选出3人担任班长、学习委员、体育委员(每人一职),有多少种选法?若只选3人组成班委(不分职务),又有多少种?

查看参考答案

① 分职务(有序)→ 排列

P(7,3) = 7 × 6 × 5 = 210 种

② 不分职务(无序)→ 组合

C(7,3) = 7×6×5 / (3×2×1) = 210/6 = 35 种

关系验证:P(7,3) = C(7,3) × 3! = 35 × 6 = 210 ✅

题2网格路径计数

题目:在一个 4×4 的网格中,从左下角走到右上角,每次只能向右或向上走一格,共有多少条不同的路径?

查看参考答案

分析:总共需要走 4步右 + 4步上 = 8步

问题转化为:8步中选4步向右(其余自动向上)

答案 = C(8,4) = 8×7×6×5 / (4×3×2×1) = 70/1 = 70

一般结论:m×n 网格的路径数 = C(m+n, m)

题3分组分配模型

题目:将6本不同的书平均分给甲、乙、丙三人,每人2本,有多少种分法?

查看参考答案

方法:逐步选取

甲选2本:C(6,2) = 15

乙从剩4本选2本:C(4,2) = 6

丙拿最后2本:C(2,2) = 1

总数 = 15 × 6 × 1 = 90 种

⚠️ 注意:如果题目是"分成三堆(不分给谁)",则还需除以 3! = 6,答案为 90/6 = 15。

区分关键:分配对象是否可区分!人可区分→不除;堆不可区分→要除。

模块 04

总结提升

1核心要点总结
知识板块必须记住的核心
加法原理分类计数,各类互斥,求和
乘法原理分步计数,步步必需,求积
排列 P(n,m)n!/(n-m)!;有序选取
组合 C(n,m)n!/(m!(n-m)!);无序选取
核心关系P(n,m) = C(n,m) × m!
杨辉三角C(n,m)=C(n-1,m-1)+C(n-1,m)
对称性C(n,m) = C(n,n-m)
卡特兰数Cat(n)=C(2n,n)/(n+1);括号/栈/二叉树
2拓展:容斥原理

💡 当"直接计数"困难时

容斥原理:|A∪B| = |A| + |B| - |A∩B|

三个集合:|A∪B∪C| = |A|+|B|+|C| - |A∩B|-|A∩C|-|B∩C| + |A∩B∩C|

应用场景:"至少满足一个条件"的计数

例:1~100中能被3或5整除的数的个数

= ⌊100/3⌋ + ⌊100/5⌋ - ⌊100/15⌋ = 33 + 20 - 6 = 47

3思考与启发

💡 学完本讲,你应该掌握的6项能力

1. 能准确区分加法原理和乘法原理的使用场景。

2. 能判断一个问题该用排列还是组合(有序vs无序)。

3. 熟练计算 P(n,m) 和 C(n,m),掌握递推法避免溢出。

4. 理解杨辉三角的递推关系及其组合意义。

5. 识别卡特兰数的经典模型(括号、栈、二叉树)。

6. 了解容斥原理的基本思想,处理"至少一个"类问题。

模块 05

学习检测

5 个初赛高频易错点,每个都有口诀帮你记住。

易错1

排列组合分不清

❌ 错误
"选3人参加比赛"用了P(10,3)
比赛不分名次,不应考虑顺序!
✅ 正确
不分角色/名次 → C(n,m)
分角色/有名次 → P(n,m)
问自己:"交换两人算不同方案吗?"
口诀:有序P无序C,交换试试就知道!
易错2

分组忘记除以组数的阶乘

❌ 错误
6本书均分3堆:C(6,2)×C(4,2)×C(2,2)=90
堆是不可区分的,90包含了重复!
✅ 正确
均分k堆(堆不可区分)→ 除以 k!
90 / 3! = 90/6 = 15
若分给k个人(人可区分)→ 不除
口诀:均分堆要除阶乘,分给人就不用除!
易错3

C(n,m) 计算中间溢出

❌ 错误
n! / (m! * (n-m)!)
n! 可能远超 long long 范围
✅ 正确
用递推:C[n][m]=C[n-1][m-1]+C[n-1][m]
或边乘边除:res*(n-i)/(i+1)
口诀:组合数别算阶乘,递推或边乘边除!
易错4

重复计数:同一元素被多次选取

❌ 错误
5人选3人当干部,允许兼职
用了 C(5,3) ← 这不允许兼职!
✅ 正确
允许重复选取 → 可重排列/组合
每个职位独立选人:5³ = 125
C(n,m) 默认不重复选取
口诀:C和P都不重复,可重另用新公式!
易错5

杨辉三角行列号搞混

❌ 错误
认为第3行第2个数是C(3,2)=3
(从1开始计数的话)
✅ 正确
杨辉三角通常从0开始编号
第n行第m个 = C(n,m)
第3行:1 3 3 1 → C(3,0)..C(3,3)
口诀:杨辉三角从0数,第n行第m个=C(n,m)!
速查组合数学速查表
知识点公式 / 结论
加法原理分类求和:|A∪B| = |A|+|B|(互斥时)
乘法原理分步求积:总 = 步骤1 × 步骤2 × ...
P(n,m)n!/(n-m)! = n×(n-1)×...×(n-m+1)
C(n,m)n!/(m!(n-m)!) = P(n,m)/m!
对称性C(n,m) = C(n,n-m)
杨辉递推C(n,m) = C(n-1,m-1) + C(n-1,m)
二项式和ΣC(n,k) = 2ⁿ
卡特兰数Cat(n) = C(2n,n)/(n+1)
容斥(2集)|A∪B| = |A|+|B|-|A∩B|
📌知识点笔记卡

➕✖️ 计数原理

分类→加法,分步→乘法

做完=加法,没做完=乘法

一切计数的基石

📊 排列 P(n,m)

有序选取,n!/(n-m)!

连乘m个递减整数

P(n,n)=n! 全排列

🎯 组合 C(n,m)

无序选取,P/m!

C(n,m)=C(n,n-m)

递推或边乘边除

🔺 杨辉三角

C(n,m)=左上+右上

第n行之和=2ⁿ

组合意义的完美体现

🐱 卡特兰数

Cat(n)=C(2n,n)/(n+1)

1,1,2,5,14,42...

括号/栈/二叉树/路径

🔄 容斥原理

|A∪B|=|A|+|B|-|A∩B|

"至少一个"的利器

奇加偶减交替进行

课后练习

分层练习作业

A基础 / B提高 / C挑战,难度递增,点击展开答案与解析。

🟢 A组 · 基础(4题)

A1选择题

C(6, 2) = ()

A. 12   B. 15   C. 30   D. 36

查看参考答案

答案:B. 15

C(6,2) = 6×5 / (2×1) = 30/2 = 15

考点:组合数 C(n,m) 表示「从 n 个不同元素中取 m 个、不计顺序」的取法数,公式为 n!/(m!(n−m)!)。

易错:算成 6×5=30,忘记除以 2! 去序。

A2选择题

P(4, 3) = ()

A. 4   B. 12   C. 24   D. 64

查看参考答案

答案:C. 24

P(4,3) = 4×3×2 = 24

考点:排列数 P(n,m) 计较顺序,等于从 n 开始连续往下乘 m 个因子:n×(n−1)×…×(n−m+1)。

易错:与组合数混淆,错选 C(4,3)=4,忽略了取出的 3 个元素还要排顺序。

A3选择题

从5人中选2人参加座谈会(不分角色),选法种数是()

A. 10   B. 20   C. 25   D. 60

查看参考答案

答案:A. 10

不分角色→组合:C(5,2) = 5×4/2 = 10

考点:题干强调「不分角色」,说明两人交换位置是同一种选法,应当用组合而不是排列。

易错:看到「从 5 人中选 2 人」就按排列算成 5×4=20。

A4选择题

杨辉三角第5行(从第0行开始)的所有数之和是()

A. 16   B. 32   C. 64   D. 10

查看参考答案

答案:B. 32

第n行之和 = 2ⁿ,第5行 = 2⁵ = 32。
验证:1+5+10+10+5+1 = 32 ✅

考点:杨辉三角第 n 行恰好是 (1+1)n 的二项式系数,所以该行所有数之和等于 2n。

易错:把「第 5 行」当成只有 5 个数,或误以为从第 1 行起算而得 24=16。

🟡 B组 · 提高(4题)

B1填空题

3×3网格从左下到右上的路径数 = C(____, ____) = ______

查看参考答案
C++完整参考代码
#include <iostream>
using namespace std;

int main() {
    int n = 6, m = 3;                  // 求 C(6, 3)

    // 方法一:组合数公式 C(n,m) = [n(n-1)…(n-m+1)] / m!
    // 边乘边除,每一步结果都是整数,可避免中间溢出
    long long c = 1;
    for (int i = 1; i <= m; i++)
        c = c * (n - m + i) / i;       // 依次乘 4、5、6,依次除 1、2、3
    cout << "C(6,3) = " << c << endl;  // 20

    // 方法二:杨辉三角递推 C(n,m) = C(n-1,m-1) + C(n-1,m)
    long long tri[10][10] = {0};
    for (int i = 0; i <= n; i++) {
        tri[i][0] = 1;                 // 每行第一个都是 1
        for (int j = 1; j <= i; j++)
            tri[i][j] = tri[i - 1][j - 1] + tri[i - 1][j];
    }
    cout << "杨辉三角 C(6,3) = " << tri[n][m] << endl;   // 20
    return 0;
}

答案:C(6, 3) = 20。所以 3×3 网格从左下走到右上共有 20 条最短路径。

思路:从左下走到右上,一共要走 3 步向右 + 3 步向上 = 6 步。只要决定"这 6 步里哪 3 步是向右",整条路线就唯一确定了,所以有 C(6,3) 种走法:C(6,3) = 6×5×4 ÷ (3×2×1) = 120 ÷ 6 = 20。程序里给了两种实现:公式法(边乘边除)和杨辉三角递推法(C(n,m)=C(n-1,m-1)+C(n-1,m),本质就是程序里的网格 DP f[i][j] = f[i-1][j] + f[i][j-1])。

考点:组合数 C(n,m) 的意义与公式、杨辉三角递推、"网格路径 = 组合计数"这个经典模型。

易错:① 数步数别弄错:3×3 网格要走 3 步右 + 3 步上共 6 步,所以是 C(6,3),不是 C(3,3);② 公式里分子是 6×5×4、分母是 3×2×1,别只除一半;③ 数据范围要留意:组合数增长极快——C(20,10) = 184756、C(30,15) = 155117520 都还装得下 int,但 C(34,17) = 2333606220 就已经超过 int 上限 2147483647,C(67,33) = 14226520737620288370 更是连 64 位整数都装不下,这时要用 long long、高精度,或者直接在模意义下用杨辉三角 / 逆元来算。

B2选择题

将4封不同的信投入3个不同的信箱,每封信都可以投任意信箱,共有()种投法

A. 12   B. 64   C. 81   D. 24

查看参考答案

答案:C. 81

每封信有3种选择,4封信独立:3⁴ = 81。
这是可重排列,不是P也不是C!

考点:「每封信可自由选择信箱」是分步计数:4 封信各做一次独立选择,把每步的方案数相乘即 3×3×3×3。

易错:误用隔板法 C(3+4−1,4)=15,隔板法只适用于「相同物品」,而信是互不相同的。

B3选择题

C(10,3) + C(10,4) = ()

A. C(10,7)   B. C(11,4)   C. C(11,3)   D. C(20,7)

查看参考答案

答案:B. C(11,4)

杨辉三角递推:C(n,m)+C(n,m+1)=C(n+1,m+1)
C(10,3)+C(10,4)=C(11,4)=330

考点:这是杨辉三角(帕斯卡)递推恒等式 C(n,m) + C(n,m+1) = C(n+1,m+1) 的直接应用。

易错:把下标或上标直接相加,错拼成 C(20,7) 之类不成立的组合数。

B4选择题

3对括号的合法排列数是()

A. 3   B. 5   C. 6   D. 10

查看参考答案

答案:B. 5

卡特兰数 Cat(3) = C(6,3)/4 = 20/4 = 5
列举:((())), (()()), (())(), ()(()), ()()()

考点:n 对括号的合法排列数是卡特兰数 Cat(n) = C(2n,n)/(n+1),它同时对应出栈序列、二叉树形态等问题。

易错:直接把 C(6,3)=20 当作答案,忘了要去掉形如 )( 开头的非法序列。

🔴 C组 · 挑战(4题)

C1初赛真题

10个人站成一排,其中甲乙必须相邻,共有()种排法

A. 2×9!   B. 9!   C. 10!   D. 2×10!

查看参考答案

答案:A. 2×9!

捆绑法:把甲乙绑在一起看作1个整体,共9个元素全排列=9!

甲乙内部可以互换:×2

总计 = 2 × 9! = 2 × 362880 = 725760

考点:「必须相邻」用捆绑法:把甲乙看成一个整体参与排列,再乘上整体内部的顺序。

易错:只算 9! 就交卷,忘记甲乙两人还可以互换位置,漏乘 2。

C2初赛真题

从1~100中任取两个不同的数,使它们的和为偶数,共有()种取法

A. 2450   B. 2500   C. 4950   D. 5000

查看参考答案

答案:A. 2450

和为偶数 → 两数同奇或同偶

奇数50个:C(50,2)=50×49/2=1225

偶数50个:C(50,2)=1225

总计 = 1225+1225 = 2450(加法原理)

考点:按奇偶分类讨论:两数之和为偶数,当且仅当它们同奇或同偶,再用加法原理把两类取法相加。

易错:直接用 C(100,2)=4950 当答案,忽略「同奇或同偶」这一限制条件。

C3初赛真题

n个元素的栈,合法的出栈序列数为Cat(n)。Cat(4) = ()

A. 5   B. 14   C. 42   D. 132

查看参考答案

答案:B. 14

Cat(4) = C(8,4)/5 = 70/5 = 14

卡特兰数前几项:Cat(0)=1, Cat(1)=1, Cat(2)=2, Cat(3)=5, Cat(4)=14

考点:卡特兰数满足递推 Cat(n) = C(2n,n)/(n+1),n 个元素的合法出栈序列数正是 Cat(n)。

易错:与 4! = 24 混淆,或错把 C(8,4) = 70 当作答案而漏除 n+1。

C4初赛真题

将5本不同的书分给3个人,每人至少1本,共有()种分法

A. 150   B. 180   C. 240   D. 540

查看参考答案

答案:A. 150

方法:容斥原理

无限制分配:3⁵ = 243

减去至少1人空手:C(3,1)×2⁵ = 3×32 = 96

加回至少2人空手:C(3,2)×1⁵ = 3×1 = 3

243 - 96 + 3 = 150

考点:「每人至少 1 本」适合用容斥原理:先算无限制方案数 35,再扣去有人空手的情况并逐层加减。

易错:只用 3⁵ − C(3,1)×2⁵ 就结束,漏掉最外层「加回至少 2 人空手」的 +3 这一项。