Part05 数学
CSP-J 初赛常考知识点总结 - 数学篇
1.初等数论
1.1 整除、因数、倍数、指数
- 整除:如果整数 aaa 除以整数 bbb (b≠0b \neq 0b=0) 的商是整数且余数为 0,则称 bbb 整除 aaa,记作 b∣ab \mid ab∣a
- 因数与倍数:如果 b∣ab \mid ab∣a,则 bbb 是 aaa 的因数,aaa 是 bbb 的倍数
- 指数:表示相同因数连乘的运算,如 an=a×a×⋯×aa^n = a \times a \times \cdots \times aan=a×a×⋯×a(n 个 a 相乘)
1.2 取整运算
- 向下取整(地板函数):⌊x⌋\lfloor x \rfloor⌊x⌋ 表示不超过 xxx 的最大整数
- 向上取整(天花板函数):⌈x⌉\lceil x \rceil⌈x⌉ 表示不小于 xxx 的最小整数
- 四舍五入:round(x) 表示最接近 xxx 的整数
// C++ 中的取整函数
#include <cmath>
double x = 3.7;
floor(x); // 3.0
ceil(x); // 4.0
round(x); // 4.0
1.3 模运算与同余
- 模运算:a mod ma \bmod mamodm 表示 aaa 除以 mmm 的余数,满足 0≤a mod m<m0 \leq a \bmod m < m0≤amodm<m
- 同余:如果 a mod m=b mod ma \bmod m = b \bmod mamodm=bmodm,则称 aaa 与 bbb 模 mmm 同余,记作 a≡b(modm)a ≡ b \pmod{m}a≡b(modm)
- 模运算性质:
- (a+b) mod m=(a mod m+b mod m) mod m(a + b) \bmod m = (a \bmod m + b \bmod m) \bmod m(a+b)modm=(amodm+bmodm)modm
- (a−b) mod m=(a mod m−b mod m+m) mod m(a - b) \bmod m = (a \bmod m - b \bmod m + m) \bmod m(a−b)modm=(amodm−bmodm+m)modm
- (a×b) mod m=(a mod m×b mod m) mod m(a × b) \bmod m = (a \bmod m × b \bmod m) \bmod m(a×b)modm=(amodm×bmodm)modm
1.4 整数唯一分解定理
定理内容:任何大于 1 的整数都可以唯一地分解为质因数的幂的乘积形式:
n=p1a1×p2a2×⋯×pkak
n = p_1^{a_1} × p_2^{a_2} × \cdots × p_k^{a_k}
n=p1a1×p2a2×⋯×pkak
其中 p1,p2,…,pkp_1, p_2, \ldots, p_kp1,p2,…,pk 是质数,a1,a2,…,aka_1, a_2, \ldots, a_ka1,a2,…,ak 是正整数。
// 质因数分解
vector<pair<int, int>> primeFactorization(int n) {vector<pair<int, int>> factors;for (int i = 2; i * i <= n; i++) {if (n % i == 0) {int count = 0;while (n % i == 0) {count++;n /= i;}factors.push_back({i, count});}}if (n > 1) {factors.push_back({n, 1});}return factors;
}
1.5 最大公约数与最小公倍数
基本概念
- 最大公约数 (GCD):两个或多个整数的最大公有因数
- 最小公倍数 (LCM):两个或多个整数的最小公有倍数
计算方法
短除法
适用于较小数字,计算过程:
261520331510515102112
\begin{array}{c|ccc}
2 & 6 & 15 & 20 \\
3 & 3 & 15 & 10 \\
5 & 1 & 5 & 10 \\
2 & 1 & 1 & 2 \\
\end{array}
235263111515512010102
- 最大公约数:222(左侧能被所有数整除的数的乘积)
- 最小公倍数:2×3×5×2×1×1×2=1202 \times 3 \times 5 \times 2 \times 1 \times 1 \times 2 = 1202×3×5×2×1×1×2=120
1.6 辗转相除法(欧几里得算法)
适用于较大数字,递归公式:
gcd(a,b)={aif b=0gcd(b,a mod b)otherwise
\gcd(a,b) = \begin{cases}
a & \text{if } b = 0 \\
\gcd(b, a \bmod b) & \text{otherwise}
\end{cases}
gcd(a,b)={agcd(b,amodb)if b=0otherwise
示例:求 gcd(437,323)\gcd(437, 323)gcd(437,323)
437÷323=1 余 114323÷114=2 余 95114÷95=1 余 1995÷19=5 余 0
\begin{align*}
437 \div 323 &= 1 \text{ 余 } 114 \\
323 \div 114 &= 2 \text{ 余 } 95 \\
114 \div 95 &= 1 \text{ 余 } 19 \\
95 \div 19 &= 5 \text{ 余 } 0 \\
\end{align*}
437÷323323÷114114÷9595÷19=1 余 114=2 余 95=1 余 19=5 余 0
∴ gcd(437,323)=19\gcd(437, 323) = 19gcd(437,323)=19
C++ 模板代码
// 递归实现
int gcd(int a, int b) {return b == 0 ? a : gcd(b, a % b);
}// 迭代实现
int gcd(int a, int b) {while (b != 0) {int temp = b;b = a % b;a = temp;}return a;
}// 最小公倍数
int lcm(int a, int b) {return a / gcd(a, b) * b; // 先除后乘避免溢出
}
关系公式
对于两个数 aaa 和 bbb:
lcm(a,b)=∣a×b∣gcd(a,b)
\text{lcm}(a,b) = \frac{|a \times b|}{\gcd(a,b)}
lcm(a,b)=gcd(a,b)∣a×b∣
1.7 质数筛法
埃拉托斯特尼筛法(埃氏筛)
原理:从2开始,将每个质数的倍数都标记为合数
时间复杂度:O(nloglogn)O(n \log \log n)O(nloglogn)
空间复杂度:O(n)O(n)O(n)
// vis[i] 标记合数,p[i] 质数列表
void sieve(int n) {vis[0] = vis[1] = true;for (int i = 2; i * i <= n; i++)if (vis[i])for (int j = i * i; j <= n; j += i)vis[j] = true;for(int i=1;i<=n;i++)if(!vis[i])p[++tot] = i;
}
欧拉筛(线性筛)
原理:每个合数只被它的最小质因子筛掉一次
时间复杂度:O(n)O(n)O(n)
空间复杂度:O(n)O(n)O(n)
void eulerSieve(int n) {for (int i = 1; i <= n; i++) {if (!vis[i])p[++tot] = i;for (int j = 1; j <= tot && p[j] * i <= n; j++) {vis[p[j] * i] = true;if (i % p[j] == 0)break;}}
}
2.离散与组合数学
2.1 集合
- 集合:具有某种特定性质的事物的总体
- 子集:如果集合 A 的所有元素都属于集合 B,则称 A 是 B 的子集,记作 A⊆BA ⊆ BA⊆B
- 交集:A∩B={x∣x∈A 且 x∈B}A ∩ B = \{x \mid x ∈ A \text{ 且 } x ∈ B\}A∩B={x∣x∈A 且 x∈B}
- 并集:A∪B={x∣x∈A 或 x∈B}A ∪ B = \{x \mid x ∈ A \text{ 或 } x ∈ B\}A∪B={x∣x∈A 或 x∈B}
- 补集:∁UA={x∣x∈U 且 x∉A}\complement_UA = \{x \mid x ∈ U \text{ 且 } x ∉ A\}∁UA={x∣x∈U 且 x∈/A}
2.2 排列组合
基本原理
-
加法原理:完成工作有 nnn 类方法,第 iii 类有 aia_iai 种方式,总方法数:
S=a1+a2+⋯+anS = a_1 + a_2 + \cdots + a_nS=a1+a2+⋯+an -
乘法原理:完成工作有 nnn 个步骤,第 iii 步有 aia_iai 种方式,总方法数:
S=a1×a2×⋯×anS = a_1 \times a_2 \times \cdots \times a_nS=a1×a2×⋯×an
排列 (Arrangement/Permutation)
从 nnn 个不同元素中取 mmm 个按顺序排列:
Anm=n(n−1)(n−2)⋯(n−m+1)=n!(n−m)!
A_n^m = n(n-1)(n-2)\cdots(n-m+1) = \frac{n!}{(n-m)!}
Anm=n(n−1)(n−2)⋯(n−m+1)=(n−m)!n!
全排列:Ann=n!=1×2×3×⋯×nA_n^n = n! = 1 \times 2 \times 3 \times \cdots \times nAnn=n!=1×2×3×⋯×n
2.3 组合 (Combination)
从 nnn 个不同元素中取 mmm 个不考虑顺序:
Cnm=Anmm!=n!m!(n−m)!
C_n^m = \frac{A_n^m}{m!} = \frac{n!}{m!(n-m)!}
Cnm=m!Anm=m!(n−m)!n!
组合恒等式
Cnm=Cnn−m C_n^m = C_n^{n-m} Cnm=Cnn−m
解题技巧
1. 先选后排
先将元素选出,再进行排列
2. 特殊优先
特殊元素或位置优先处理
3. 分排用直排
多排问题可视为单排处理
4. 分类法
直接计算符合条件的数目
5. 排除法(正难则反)
计算不符合条件的数目,再从总数中减去
6. 捆绑法
mmm 个必须相邻的元素捆绑处理:
S=An−m+1n−m+1×Amm
S = A_{n-m+1}^{n-m+1} \times A_m^m
S=An−m+1n−m+1×Amm
7. 插空法
mmm 个不能相邻的元素先排其他元素再插空:
S=An−mn−m×An−m+1m
S = A_{n-m}^{n-m} \times A_{n-m+1}^m
S=An−mn−m×An−m+1m
8. 隔板法
将 nnn 个相同元素分成 mmm 组,每组至少一个:
S=Cn−1m−1
S = C_{n-1}^{m-1}
S=Cn−1m−1
9. 定序问题
nnn 个元素中有 mmm 个必须按特定顺序排列:
S=AnnAmm
S = \frac{A_n^n}{A_m^m}
S=AmmAnn
2.4 杨辉三角(帕斯卡三角形)
杨辉三角是二项式系数在三角形中的一种几何排列,具有以下性质:
- 第 nnn 行第 kkk 个数等于 Cn−1k−1C_{n-1}^{k-1}Cn−1k−1
- 每个数等于它上方两数之和
- 第 nnn 行的数字和为 2n−12^{n-1}2n−1
行号: 二项式系数
1: 1
2: 1 1
3: 1 2 1
4: 1 3 3 1
5: 1 4 6 4 1
// 生成杨辉三角的前 n 行,使用二维数组存储
int generatePascalTriangle(int n) {for (int i = 0; i < n; i++) {triangle[i][0] = 1; // 每行第一个元素为1triangle[i][i] = 1; // 每行最后一个元素为1// 计算中间元素for (int j = 1; j < i; j++)triangle[i][j] = triangle[i - 1][j - 1] + triangle[i - 1][j];}
}
3. 其他
3.1 进制转换
进制表示法
- 16进制:H (Hexadecimal)
- 10进制:D (Decimal)
- 8进制:O (Octonary)
- 2进制:B (Binary)
转换方法
nnn 进制转十进制
公式:
x(10)=∑i=0k−1ai×ni
x_{(10)} = \sum_{i=0}^{k-1} a_i \times n^i
x(10)=i=0∑k−1ai×ni
其中 aia_iai 是第 iii 位上的数字。
示例:
- 10010110(2)=1×27+0×26+0×25+1×24+0×23+1×22+1×21+0×20=150(10)10010110_{(2)} = 1×2^7 + 0×2^6 + 0×2^5 + 1×2^4 + 0×2^3 + 1×2^2 + 1×2^1 + 0×2^0 = 150_{(10)}10010110(2)=1×27+0×26+0×25+1×24+0×23+1×22+1×21+0×20=150(10)
- KaTeX parse error: Expected '}', got 'EOF' at end of input: …= 0.3125_{(10)}
十进制转 nnn 进制
整数部分:除 nnn 取余,逆序排列
小数部分:乘 nnn 取整,顺序排列
示例:13(10)=1101(2)13_{(10)} = 1101_{(2)}13(10)=1101(2)
13÷2=6 余 16÷2=3 余 03÷2=1 余 11÷2=0 余 1
\begin{align*}
13 \div 2 &= 6 \text{ 余 } 1 \\
6 \div 2 &= 3 \text{ 余 } 0 \\
3 \div 2 &= 1 \text{ 余 } 1 \\
1 \div 2 &= 0 \text{ 余 } 1 \\
\end{align*}
13÷26÷23÷21÷2=6 余 1=3 余 0=1 余 1=0 余 1
C++ 模板代码
// n进制转十进制
int nToDecimal(string num, int base) {int result = 0;for (char c : num) {int digit = (c >= '0' && c <= '9') ? c - '0' : c - 'A' + 10;result = result * base + digit;}return result;
}// 十进制转n进制
string decimalToN(int num, int base) {if (num == 0) return "0";string result;while (num > 0) {int remainder = num % base;char digit = (remainder < 10) ? '0' + remainder : 'A' + remainder - 10;result = digit + result;num /= base;}return result;
}
nnn 进制转 mmm 进制
以十进制为中介:
n-进制→十进制→m-进制
n\text{-进制} \rightarrow \text{十进制} \rightarrow m\text{-进制}
n-进制→十进制→m-进制
3.2 ASCII 码
基本概念
- ASCII(American Standard Code for Information Interchange):美国信息交换标准代码
- 使用7位二进制数(共128个字符)表示所有英文字母、数字和常用符号
- 标准ASCII码范围:0~127(十六进制:00~7F)
ASCII 码表分类
范围(十进制) | 类别 | 说明 |
---|---|---|
0~31, 127 | 控制字符 | 通信专用字符,如换行(10)、回车(13) |
32 | 空格字符 | 空格(32) |
33~47, 58~64, 91~96, 123~126 | 特殊符号 | 标点符号和运算符 |
48~57 | 数字 | 0-9,按顺序排列 |
65~90 | 大写字母 | A-Z,按字母表顺序 |
97~122 | 小写字母 | a-z,按字母表顺序 |
重要ASCII码值
- ‘0’ = 48
- ‘A’ = 65
- ‘a’ = 97
- 空格 = 32
- 换行符 = 10
- 回车符 = 13
应用示例
// C++中字符与ASCII码的转换
char c = 'A';
int ascii = (int)c; // 65
char fromAscii = (char)65; // 'A'// 大小写转换(利用ASCII码差值为32)
char lower = 'A' + 32; // 'a'
char upper = 'a' - 32; // 'A'
3.3 格雷码(Gray Code)
基本概念
- 格雷码:一种循环二进制编码,相邻两个编码只有一位不同
- 优点:减少数字变化时产生的错误,常用于模拟数字转换、旋转编码器等
生成规则
- 1位格雷码:0, 1
- n位格雷码 = (n-1)位格雷码顺序排列 + (n-1)位格雷码逆序排列,并在前面分别加0和1
格雷码与二进制转换
二进制转格雷码
Gi={Bii=n−1Bi⊕Bi+1i<n−1 G_i = \begin{cases} B_i & i = n-1 \\ B_i \oplus B_{i+1} & i < n-1 \end{cases} Gi={BiBi⊕Bi+1i=n−1i<n−1
其中 BiB_iBi 是二进制数的第i位,GiG_iGi 是格雷码的第i位,⊕\oplus⊕ 表示异或运算
格雷码转二进制
Bi={Gii=n−1Gi⊕Bi+1i<n−1 B_i = \begin{cases} G_i & i = n-1 \\ G_i \oplus B_{i+1} & i < n-1 \end{cases} Bi={GiGi⊕Bi+1i=n−1i<n−1
C++ 实现代码
// 二进制转格雷码
int binaryToGray(int num) {return num ^ (num >> 1);
}// 格雷码转二进制
int grayToBinary(int gray) {int binary = gray;while (gray >>= 1) {binary ^= gray;}return binary;
}// 生成n位格雷码序列
vector<int> generateGrayCode(int n) {vector<int> grayCodes;int size = 1 << n; // 2^nfor (int i = 0; i < size; i++) {grayCodes.push_back(i ^ (i >> 1));}return grayCodes;
}
应用示例
- 3位格雷码序列:000, 001, 011, 010, 110, 111, 101, 100
- 在数字电路中,格雷码可以减少信号切换时的错误
- 在旋转编码器中,使用格雷码可以准确检测旋转方向
习题参考
- CSP 2019 入门组第一轮-T7:排列组合应用
- CSP 2019 入门组第一轮-T9:质数判断
- CSP 2019 入门组第一轮-T10:最大公约数计算
- CSP 2019 入门组第一轮-T13:组合数学(重点复习)
- CSP 2020 入门组第一轮-T9:进制转换
- CSP 2020 入门组第一轮-T14:排列组合应用
- CSP 2020 第一轮模拟-T11:组合数学
筛法选择建议:
- 埃氏筛:代码简单,适合小范围数据(n≤106n \leq 10^6n≤106)
- 欧拉筛:效率更高,适合大范围数据(n≤107n \leq 10^7n≤107),且需要记录质数列表