组合基础与数论基础
注: \(\log x = \ln x\)
组合基础
- 加法原理、乘法原理
- 排列数 \(A^m_n = \frac{n!}{(n-m)!}\) : 从 \(1 \sim n\) 选 \(m\) 个数排成一列的方案数
- 组合数 \(C^m_n = \binom{n}{m} = \frac{n!}{(n-m)!m!}\) : 从\(1 \sim n\) 选 \(m\) 个数的方案数。(相对于排列数不考虑顺序)
- \(C^m_n = C^{n-m}_n\)
- \(C^m_n = \frac{n}{m} \times C^{m-1}_{n-1}\)
- \(C^m_n = C^{m-1}_{n-1} + C^m_{n-1}\) (选第 \(n\) 个 + 不选第 \(n\) 个) (杨辉三角)
- \(C^0_n = 1\)
- \(C^1_n = n\)
- \(C^2_n = \frac{(n-1)n}{2}\)
- 二项式定理: \((x + y) ^ n = \sum\limits^n_{k=0}{C^{n-k}_nx^{n-k}y^k}\)
数论基础
- 在 \(1 \sim n\) 大约有 \(\frac{n}{\ln n}\) 个质数,平均每 \(\ln n\) 个数就有 \(1\) 个质数。
- 找第一个大于或小于 \(n\) 的质数,直接从 \(n\) 开始枚举,然后用试除法判断,时间复杂度 \(O(\sqrt n\log n)\)
- 试除法、埃氏筛、线性筛。
- 算数基本定理
- 设 \(n\) 是大于 \(1\) 的整数
- 它的正约数集合是 \(\{\prod\limits^m_{i=1}{p_i^{b_i}}\}, b_i \in [0, c_i] \cap \mathbb{Z}\)
- 它的正约数个数为 \(\prod\limits^n_{i=1}{(c_i+1)}\)
- 它的正约数之和为 \(\prod\limits^m_{i=1}{(\sum\limits^{c_i}_{j=0}p_i^j)}\)
- 一个数 \(n\) 至多只有一个质因数大于 \(\sqrt n\)
- 一个数的因子总是成对出现,除完全平方数外。
- 一个数 \(n\) 的因数个数小于 \(2 \sqrt n\)
- \(1 \sim n\) 每个数的约数个数总和大约有 \(n \log n\) 个。
- \(\gcd(na,nb) = n\gcd(a,b), \text{lcm}(na,nb)=n\text{lcm}(a,b)\)
- \(a \cdot b = \gcd(a, b) \cdot \text{lcm}(a, b)\)
- \(\gcd(\frac{a}{\gcd(a,b)},\frac{b}{\gcd(a,b)})=1, \gcd(\frac{\text{lcm}(a, b)}{a},\frac{\text{lcm}(a, b)}{b}) = 1\)
- \(a > b >0, \gcd(a,b) = \gcd(a,a-b) = \gcd(b,a-b)\)
- \(\gcd(a, b) = \gcd(b, a \bmod b)\)
质数
质数又称素数。一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做质数。
在 \(1 \sim n\) 大约有 \(\frac{n}{\ln n}\) 个质数,平均每 \(\ln n\) 个数就有 \(1\) 个质数。
判定
根据素数的定义,可以写出一下代码,时间复杂度 \(O(\sqrt n)\)
算法一,试除法:
bool is_prime(int x) {
if(x < 2)
return false;
for(int i = 2; i * i <= x; i++)
if(x % i == 0)
return false;
return true;
}
找第一个大于或小于 \(n\) 的质数,直接从 \(n\) 开始枚举,然后用试除法判断,时间复杂度 \(O(\sqrt n\log n)\)
判断 \(1 \sim n\) 之间是否是质数,时间复杂度 \(O(n \sqrt n)\) ,效率太低。
算法二:
bool v[N];
void solve_primes(int n) {
memset(v, 0x00, siaeof(v));
v[0] = v[1] = 1;
for(int i = 2; i <= n; i++)
for(int j = 2; i * j <= n; j++)
v[i * j] = 1;
}
标记每个数的倍数,最后 \(v_x = 0\) 的 \(x\) 是质数。但是和数会标记多次。
时间复杂度 \(O(\sum\limits^n_{i=1}{\frac{n}{i}}) = O(n\sum\limits^n_{i=1}{\frac{1}{i}}) = O(n \log n)\) (调和级数)
算法三, \(\text{Eratosthenes}\) 筛:
bool v[N];
void solve_primes(int n) {
memset(v, 0x00, siaeof(v));
for(int i = 2; i <= n; i++)
if(!v[i])
for(int j = i; i * j <= n; j++)
v[i * j] = 1;
}
标记每个质数的倍数。j
从 i
开始是原来小于 i
的质数会标记 x * i
, 其中 x < i
。
但是像 \(24\) 这样的数会被 \(2,3\) 多次标记。
时间复杂度 \(O(n \log{\log{n}})\) ,证明 alfayoung - 通俗易懂的埃氏筛时间复杂度分析
算法四, \(\text{Euler}\) 筛、线性筛:
int v[N];
::std::vector<int> ps;
void solve_primes(int n) {
memset(v, 0x00, sizeof(v));
for(int i = 2; i <= n; i++>)
{
if(!v[i])
ps.push_back(v[i] = i);
for(int j : ps)
if(j > v[i] || i * j > n)
break;
else
v[i * j] = j;
}
}
用一个数的最小质因子来标记它,\(v_x\) 表示 \(x\) 的最小质因子,\(ps\) 是 \(1 \sim n\) 的质数。
每个合数 \(i \times p\) 只会被它的最小质因子 \(p\) 筛一次,时间复杂度 \(O(n)\)
算数基本定理、唯一分解定理
任何一个大于 \(1\) 的正整数都能唯一分解为有限个质数的乘积。
设 \(n\) 是大于 \(1\) 的整数,它的正约数集合是 \(\{\prod\limits^m_{i=1}{p_i^{b_i}}\}, b_i \in [0, c_i] \cap \mathbb{Z}\)
它的正约数个数为 \(\prod\limits^n_{i=1}{(c_i+1)}\) 。每个质数选多少个,根据乘法原理乘起来。
它的正约数之和为 \((p_1^0 + p_1^2 + p_1^3 + \cdots + p_1^{c_1}) \times (p_m^0 + p_m^2 + p_m^3 + \cdots + p_m^{c_m}) = \prod\limits^m_{i=1}{(\sum\limits^{c_i}_{j=0}p_i^j)}\) 。每个质数选择若干次和其它的乘起来,变成一个因子,最后若干个因子加起来。
质因数分解
一个数 \(n\) 至多只有一个质因数大于 \(\sqrt n\) 。反证法,对于正整数 \(n\) ,假设有 \(n\) 的两个因子 \(a, b > \sqrt n \land a \neq b\) ,\(a \times b > n\) ,故假设不成立,则命题成立。
int ps[N], c[N], p;
void dec(int x) {
p = 0;
for(int i = 2; i * i <= x; i++)
if(x % i == 0) {
ps[++p] = i, c[p] = 0;
while(x % i == 0)
c[p]++, x /= i;
}
if(x > 1) // x 是质数,或者存在一个质因数大于 sqrt(x)
ps[++p] = x, c[p] = 1;
}
时间复杂度 \(O(\sqrt n)\)
求 \(n\) 的因子集合
一个数的因子总是成对出现,除完全平方数外。
::std::vector<int> div;
void sol(int x) {
for(int i = 1; i * i <= x; i++)
if(x % i == 0) {
v.push_back(i);
if(i * i != x)
v.push_back(x / i);
}
}
时间复杂度 \(O(\sqrt n)\) ,根据时间复杂度可知,一个数 \(n\) 的因数个数小于 \(2 \sqrt n\)
求 \(1 \sim n\) 的因子集合
倍数法、刷表法 : 枚举一个数,看它是那个数的因数。
::std::vector<int> div[N];
void sol(int n) {
for(int i = 1; i <= n; i++)
for(int j = 1; i * j <= n; j++)
div[i * j].push_back(i);
}
时间复杂度 \(O(\frac{n}{1} + \frac{n}{2} + \frac{n}{3} + \cdots + \frac{n}{n}) = O(n \log n)\) ,根据时间复杂度可知,\(1 \sim n\) 每个数的约数个数总和大约有 \(n \log n\) 个。
约数与倍数
对于 \(a, b \in \mathbb{N}\),若存在 \(d \in \mathbb{N}\),使得 \(d|a, d|b\),则称 \(d\) 是 \(a, b\) 的公因数、公因子、公约数。记 \(\gcd(a, b)\) 为最大公因数。
对于 \(a, b \in \mathbb{N}\),若存在 \(d \in \mathbb{N}\),使得 \(a|d, b|d\),则称 \(d\) 是 \(a, b\) 的公倍数。记 \(\text{lcm}(a, b)\) 为最小公倍数。
定理
根据定义,显然有 \(\gcd(na, nb) = n \cdot \gcd(a, b)\) ,\(\text{lcm}(na, nb) = n \cdot \text{lcm}(a, b)\)
定理 1
证明:
设 \(g = \gcd(a,b)\) ,则有 \(k_1, k_2\) 满足
\(
\begin{cases}
g \cdot k_1 = a \\
g \cdot k_2 = b
\end{cases}
\) ,则原命题为 \(\gcd(k_1, k_2) = 1\) 。
反证法。假设 \(\gcd(k_1, k_2) = c > 1\),则有 \(m_1, m_2\) 满足
\(
\begin{cases}
m_1 \cdot c = k_1 \\
m_2 \cdot c = k_2
\end{cases}
\),则
\(
\begin{cases}
g \cdot m_1 \cdot c = a \\
g \cdot m_2 \cdot c = b
\end{cases}
\),则 \(\gcd(a, b) = g \cdot c \cdot \gcd(m_1, m_2)\),与 \(\gcd(a, b) = g\) 矛盾,故原命题成立。
定理 2
证明:
设 \(\gcd(a, b) = g, \text{lcm}(a, b) = l\)
有 \(k_1, k_2\) 满足
\(
\begin{cases}
k_1 \cdot g = a \\
k_2 \cdot g = b
\end{cases}
\)
\(\because \gcd(k_1, k_2) = 1 \\ \therefore l = k_1 \cdot k_2 \cdot g \\ \therefore l \cdot g = k_1 \cdot k_2 \cdot g \cdot g \\ \therefore l \cdot g = a \cdot b\)
则原命题得证。
定理 3
证明:
\(\because \text{lcm}(a, b) \cdot \gcd(a, b) = a \cdot b \\ \therefore \frac{\text{lcm}(a, b)}{a} = \frac{b}{\gcd(a, b)}, \frac{\text{lcm}(a, b)}{b} = \frac{a}{\gcd(a, b)} \\ \therefore \gcd(\frac{\text{lcm}(a, b)}{a},\frac{\text{lcm}(a, b)}{b}) = \gcd(\frac{a}{\gcd(a,b)},\frac{b}{\gcd(a,b)})=1\)
则原命题得证。
定理 4 更相减损术
证明:
设,集合 \(A,B,C\) 分别是 \(a,b\)、\(a,a-b\)、\(b,a-b\) 的公因子集合。
对于 \(d \in A\),有 \(k_1, k_2\) 满足
\(
\begin{cases}
k_1 \cdot d = a \\
k_2 \cdot d = b
\end{cases}
\),则 \(a - b = (k_1 - k_2) \cdot d\)。所以 \(A \subseteq B, A \subseteq C\)
对于 \(d \in B\),有 \(k_1, k_2\) 满足
\(
\begin{cases}
k_1 \cdot d = a \\
k_2 \cdot d = a - b
\end{cases}
\),则 \(a + (a + b) = b = (k_1 - k_2) \cdot d\)。所以 \(B \subseteq A, B \subseteq C\),又 \(A \subseteq B, A \subseteq C\),所以 \(A = B = C\),则原命题得证。
定理 5 辗转相除法、欧几里得算法
证明:
当 \(a \leq b\) 时,命题显然成立。
当 \(a > b\) 时,有 \(a = k \cdot b + z, z = a \bmod b\)。设,集合 \(A,B\) 分别是 \(a,b\)、\(b,z\) 的公因子集合。
对于 \(d \in A\),则 \(d|a, d|b\),有 \(d|kb\),则 \(d|(a-kb)\),即 \(d | z\) ,所以 \(A \subseteq B\)
对于 \(d \in B\),则 \(d|b, d|z\),有 \(d|(a - kb)\),则 \(d | a\),所以 \(B \subseteq A\),综上 \(A = B\),则原命题得证。