数论基本概念
1. 整除法
2. 算数基本定理
$p_i$ 为素数,且 $p_i < p_{i + 1}$,则有:
3. 最大公约数与最小公倍数
4. 求一个数的约数个数
一个数的每个因子均由若干个素因子构成,第 $i$ 个素因子共有 $i + 1$ 种取法,所以总个数为($k$ 为素因子的总个数):
代码如下:
1 | int divisor (int n)//算数基本定理 |
素数筛法
1. 朴素筛法
将每一个数的所有倍数都筛去,时间复杂度为:$O(\frac{n}{2} + \frac{n}{3} + \cdots + 1)$。所以当 $\lim(n \to \infty)$ 时,近似为 $O(n\log n)$。
2. 常数优化
枚举小的那个因子。
1 | for (int i = 2;i * i <= n;++i) |
3. 线性筛
时间复杂度为 $O(n)$。
1 | void work (int n)//保证每个数最多被筛一次 |
欧几里得算法
1. 辗转相减
若 $a > b$,则 $\gcd (a,b) = \gcd (a - b,b)$。
2. 辗转相除
若 $a > b$,则 $\gcd (a,b) = \gcd (b,a \bmod b)$。
1 | int gcd (int a,int b) |
扩展欧几里得算法
由欧几里得算法可知 $ax + by = \gcd (a,b)$ 一定存在一组解。那么求解 $ax + by = c$ 时,过程如下:
不断递归得到 $\gcd (a,b) \times x + 0 \times y = \gcd (a,b)$,得到特解 $x = 1,y = 0$。
1 | int exgcd (int a,int b,int &x,int &y) |
设 $k_1 = \dfrac{a}{\gcd (a,b)},k_2 = \dfrac{b} {\gcd (a,b)}$,显然 $\gcd (k_1,k_2) = 1$。设 $x,y$ 的最小变化单位是 $d_1,d_2$,则此时 $k_1 = d_2,k_2 = d_1$,所以通解是:
欧拉函数
2. 积性函数
设 $p$ 为质数,求 $\phi(p^k)$:
同理,对于两个不同质数的乘积 $n = p_1^{a_1} p_2^{a_2}$,由容斥原理:
因此,欧拉函数是积性函数。
3. 计算通式
将 $n$ 进行质因数分解:
由积性函数性质:
这个公式可以直接用于计算任意正整数的欧拉函数值。
5. 代码
根据欧拉函数通式求解。
1
2
3
4
5
6
7
8
9
10void work (int n)
{
phi[1] = 1;
for (int i = 2;i <= n;++i) phi[i] = i;//先标记为自己,方便标记质数,也方便为公式法求解
for (int i = 2;i <= n;++i)
{
if (phi[i] == i)//为素数
for (int j = i;j <= n;j += i) phi[j] = phi[j] / i * (i - 1);//其中的一个 (pi - 1) / pi
}
}根据线性筛实现 $O(n)$ 的时间复杂度求解。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23void work (int n)
{
phi[1] = 1;
for (int i = 2;i <= n;++i)
{
if (!flag[i])
{
p[++cnt] = i;
phi[i] = i - 1;//素数 p 的欧拉函数为 p - 1
}
for (int j = 1;j <= cnt;++j)
{
if (i * p[j] > n) break;
flag[i * p[j]] = 1;
if (i % p[j] == 0)
{
phi[i * p[j]] = phi[i] * p[j];//若 p 能整除 n / p,则 φ (n) = φ (n / p) * p
break;
}
phi[i * p[j]] = phi[i] * (p[j] - 1);//若 p 与 n / p 互质,且 p 为质数,则 φ (n) = φ (n / p) * (p - 1)
}
}
}利用性质 $f$ 的求解。
1
2
3
4
5
6void work (int n)
{
for (int i = 1;i <= n;++i) phi[i] = i;
for (int i = 1;i <= n;++i)
for (int j = i + i;j <= n;j += i) phi[j] -= phi[i];//减去自己所有因子的值即为 φ(i)
}
欧拉定理
如果 $a,n$ 为正整数,且 $\gcd (a,n) = 1$,则 $a^ {\phi(n)} ≡ 1 \pmod n$。
已知 $a,n \in \rm{N_{+}}$,且 $\gcd (a,n) = 1$。求证 $a^{\phi(n)} \equiv 1 \pmod n$。
乘法逆元
1. 费马小定理
欧拉定理的特殊情况,当 $n$ 为质数时:
2. 计算
$a \div b \% c$ 时,假设存在 $p \times b ≡ 1 \pmod c$,则 $p$ 为 $b$ 的逆元。$a \div b \% c = a \times p \% c$。
相当于 $b,c$ 已知,则可以通过扩展欧几里得算法求逆元,但需要 $\gcd (b,c) = 1$ 时才有解。时间复杂度 $O(n \log n)$。
1 | int inv (int b,int c) |
当 $c$ 为质数时,逆元可以表示为 $b^{c - 2} \% c$,直接可以使用快速幂求解。
3. 线性求逆元
时间复杂度为 $O(n)$。
1 | void init (int n,int mod) |
4. 无法求逆元的转化
中国剩余定理
求解以下方程:
构造答案,设
所以直接通过 $n$ 次 $\texttt{exgcd}$ 求出 $s_i$,最后合并即可。
1 | ll CRT (int n,int a[],int m[]) |
整除分块
求下列式子的值。
若用朴素的算法,时间复杂度为 $O(n)$,显然会 $\texttt{TLE}$。那么再给出一种 $O(\sqrt n)$ 的做法。
先给出所有的 $\lfloor\dfrac{n}{i}\rfloor$ 的取值不会超过 $\sqrt{n}$ 种的证明:
设一段取值均为 $\lfloor\dfrac{n}{i}\rfloor$ 的区间的左、右端点分别为 $L,R$。
代码如下:
1 | for (int L = 1,R;L <= n;L = R + 1) |
组合数学基础
1. 组合数的两种表示方法
对于递推公式,是对于第 $n$ 项是否选择得出的。
2. 组合数的预处理
1 | void init () |
3. 组合数的变形
其中的$(3)$可以转化为模型。等号左边为班级中的 $n$ 个人选择候选人,然后从候选人中选一个班长与副班长,同一个人可以身兼两职,求最终方案数;等号右边为身兼两职与两个人分别当选的两种情况,有加法原理相加得到,即:
$(4)$ 也一样可以转化为模型。等号右边为班级中有 $n$ 个男生和 $n$ 个女生,从中选 $n$ 人;等号左边相当于等价的,男生选 $i$ 个,女生选 $n - i$ 个,则有
:
【摘自 CF2077C Binary Subsequence Value Sum题解】
证明 $\sum_{i=0}^nC_n^ii=n2^{n-1}$
$i=C_i^1$,则原式等于 $\sum_{i=0}^nC_n^iC_i^1$,考虑其组合意义,即先从 $n$ 个元素中选若干个,再从若干个元素里选出一个的方案数。那我们先选这一个,有 $n$ 种方案,再从剩下 $n-1$ 个元素中选出若干个,有 $2^{n-1}$ 种方案,所以是 $n2^{n-1}$。证明 $\sum_{i=0}^nC_n^ii^2=n(n+1)2^{n-2}$
考虑 $i^2=i+i(i-1)=i+2\times\frac{i(i-1)}{2}=C_i^1+2C_i^2$,则原式等于 $\sum_{i=0}^nC_n^iC_i^1+2C_n^iC_i^2$,等于 $n2^{n-1}+2\sum_{i=0}^nC_n^iC_i^2$,则我们只需解决 $\sum_{i=0}^nC_n^iC_i^2$。
考虑组合意义,即从 $n$ 个元素里选出若干个,再从若干个元素里选出两个的方案数。那我们先选出这两个,有 $\frac{n(n-1)}{2}$ 种方案,然后再从剩下的元素中选出若干个,有 $2^{n-2}$ 种方案,所以有 $n(n-1)2^{n-3}$ 种方案。
二项式定理
1. 概念
对于每一个 $x + y$ 的选择,则选 $i$ 个 $x$,剩余均选择 $y$ 时,答案为:
因此有:
2. 二项式定理的变形
隔板法
1. 题意
把 $n$ 个相同的小球,放到 $m$ 个不同的盒子中,盒子不能为空,求方案数。或者求 $x_1 + x_2 + \cdots + x_m = n$ 的正整数解。
解法 相当于在 $n - 1$ 个间隔中选择 $m - 1$ 个间隔,将其分为 $m$ 份。故为:
2. 变式
把 $n$ 个相同的小球,放到 $m$ 个不同的盒子中,盒子可以为空,求方案数。或者求 $x_1 + x_2 + \cdots + x_m = n$ 的非负整数解。
解法 相当于在先在每个盒子中放入 $1$ 个球,然后求 $n + m$ 个相同的小球放入 $m$ 个不同的盒子的方案数,盒子不能为空。故为:
错位排列
递推公式为:
对于第 $i$ 项,可以在前 $i - 1$ 个数中选一个数与第 $i$ 个数替换,共 $i - 1$ 中,然后问题变为求 $(i - 1) \times (f_{i - 2})$。也可以将前 $i - 1$ 个数中的一个数放在前 i - 1 个位置中符合条件的某一个位置,相当于求 $(i - 1) \times f_{i - 1}$ 这一新的错排。
圆排列
原来每组排列都有 $n$ 种排列等价,故方案数为:
多重集合的排列
- 集合中有 $k$ 种不同类型的对象,每种数量均为无限,从中选 $n$ 个,排列的方案数为:
- 集合中有 $k$ 种不同类型的对象,每种数量分别为 $n_1$ 至 $n_k$,从中选 $n$ 个。相当于选出 $n_1$ 个位置放第 $1$ 种,选出 $n_2$ 个位置放第 $2$ 种,以此类推。方案数为:
多重集合的组合
集合中有 $k$ 种不同类型的对象,每种数量均为无限,从中选 $n$ 个。等价于 $k$ 个相同的球放到 $n$ 个不同的盒子中,盒子可以为空。或者等价于选 $k$ 次球,每次都可以选 $n$ 种球,且选择不分先后。组合的方案数为:
康托展开
1. 计算排列的排名
设 $a_i$ 表示 $i$ 位置右边比它小的数的个数,则该排列之前的排列总数为:
倘若 $i$ 位置上的数比该数小,则在它右边的数可以随意放置,若 $i$ 位置上的数等于该数,则继续判断 $i + 1$ 位置的数的情况,以此类推。因此可以由加法原理得可知该排列之前的排列总数。所以求排名的公式为:
2. 计算特定排名的排列
即康托展开的逆展开。
利用康托展开的公式,类似进制转换的方式去确定从高到底的每一位。若排列长度为 $x$,求编号为 $0$ 开始的,编号为 $k$ 的排列。方法如下:$p = \frac{k}{(x - 1)!}$,则说明第一位右边有 $p$ 个数比它小,所以最高位为 $p + 1$,然后取余数重复操作,知道确定排列上的所有数字。
3. 求下一个排列
对于一个排列:$a_1,a_2,\cdots,a_n$。从后往前找到第一个 $p_i < p_{i + 1}$ 的位置,从后往前找到第一个 $p_j < p_i$ 的位置。最后交换 $p_i,p_j$ 并颠倒 $i$ 位置以后的所有元素即可。
斯特林数
1. 第一类斯特林数
求将 $n$ 个不同的物体摆成k个非空环的方案数。采用动态规划的做法,对于第 $i$ 个物体,可以任取一个环加入,也可以构造一个新环,故有 $dp_{n,k} = (n - 1)dp_{n - 1,k} + dp_{n - 1,k - 1}$。(当然有初始化 $dp_{0,0} = dp_{1,1} = 1$)
2.第二类斯特林数
求将 $n$ 个不同的物体分成 $k$ 个非空集合的方案数。采用动态规划的做法,对于第 $i$ 个物体,可以任取一个集合加入,也可以放入一个新集合中,故有 $k \times dp_{n - 1,k} + dp_{n - 1,k - 1}$。(当然有初始化 $dp_{i,i} = dp_{i,1} = 1$)
卡特兰数
题目描述,假如有一个 $n\times n$ 的网络,从左下角 $A$ 点走到右上角 $B$ 点且不穿越对角线的方案数。通过几何方法证明,答案为:
其它的表达形式还有:
常见应用:
- 合法的括号匹配
- $n$ 个节点二叉树的形态数
- 入栈出栈的排列总数
- 凸 $n+2$ 边形的分割
放球问题
设 $dp_{i,j}$ 表示 $i$ 个小球放到 $j$ 个盒子的方案数。
1. 球相同,盒相同,可为空。
则有:$dp_{i,j} = dp_{i,j - 1} + dp_{i - 1,j}$。
2. 球相同,盒相同,不可为空。
则有:$dp_{i,j} = dp_{i - j,j}$。
3. 球不同,盒不同,可为空。
则有:$j^i$。
4. 球不同,盒相同,不可为空。
则有:$dp_{i,j} = dp_{i - 1,j} + dp_{i - 1,j - 1}$。
5. 球不同,盒不同,不可为空。
则有:$dp_{i,j} \times {j!}$。
6. 球不同,盒相同,可为空。
枚举盒子数,则有:$dp_{i,j} = dp_{i - 1,j} + dp_{i - 1,j - 1}$。
7. 球相同,盒不同,不可为空。
隔板法,则有:$\tbinom{i - 1}{j - 1}$。
8. 球相同,盒不同,可为空。
则有:$\tbinom{i + j - 1}{j - 1}$。
卢卡斯定理
证明略。代码如下:
1 | int calc (int n,int m) |