约数
定义
设有整数 \(a\) 和 \(b\) ,如果存在整数 \(q\) 使得 \(a = b \times q\) ,则称 \(b\) 是 \(a\) 的约数, \(a\) 是 \(b\) 的倍数,记为 \(b\ |\ a\) 。
算数基本定理的推论
在算数基本定理中,任何一个大于 \(1\) 的正整数 \(N\) 都能唯一分解为有限个质数的乘积,可写作:
其中:\(c_i \in \mathbb{N}_+\) , \(p_i\) 都是质数,并且满足 \(p_1 < p_2 < \cdots<p_m\) 。
则有以下推论:
\(N\) 的正约数集合为:
\(N\) 的正约数个数为:
\(N\) 的所有正约数和为:
求 \(N\) 的正约数集合
试除法
如果 \(n\) 有约数 \(a\) 和 \(b\) ,且 \(a\times b=n\) 。如果 \(a\le\sqrt n\) ,则 \(b\ge\sqrt n\) ,反之亦然。换句话说,约数是成对出现的(除了完全平方数 \(\sqrt n\) 单独出现)。
所以,只需要扫描 \(1\sim\sqrt n\) 的每个整数 \(x\) ,判断 \(x\) 是否能整除 \(n\) ,若能,则 \(x\) 与 \(\large\frac{n}{x}\) 都是 \(n\) 的约数。时间复杂度为 \(\mathcal{O}(\sqrt n)\) 。
试除法的推论
由上述的扫描过程不难发现一个整数 \(n\) 的约数个数至多有 \(2\sqrt n\) 个。
代码
int cnt;
int num[N];
for (int i = 1; i * i <= n; i++) {
	if (!(n % i)) {
		num[++cnt] = i;
		if (i != n / i) num[++cnt] = n / i;
	}
}
倍数法
不难发现,试除法在查找单个数的约数集合效率较高,但是不适用于批量查询,我们考虑优化。
在 \(\text{Eratosthenes}\) 筛法过程中我们可发现大量数字中一般会有共同的约数,此时进行试除法就会重复判断,所以我们利用正难则反的逆向思维选择用数字 \(x\) 本身去标记它的倍数 \(x, 2x, \cdots,\large{\frac{n}{x}}x\) 。
时间复杂度为 \(\mathcal{O}\left(n + \large{\frac{n}{2}}+\large{\frac{n}{3}}+\cdots+\large{\frac{n}{n}}\right)=\mathcal{O}\left(\sum\limits_{i=1}^n\large\frac{n}{i}\right) = \mathcal{O}(n \log n)\) 。
代码
vector<int> num[N];
for (int i = 1; i <= n; i++) 
	for (int j = 1; j * i <= n; j++) 
		num[i * j].push_back(i);
倍数法的推论
由此可见, \(1\sim N\) 中每个数的约数个数总和大约为 \(n \log n\) 。
调和级数
在上述时间复杂度中出现了一个很奇怪的式子,就是:\(\large{\sum\limits_{i=1}^n\frac{n}{i}} = n\sum\limits_{i=1} ^n\frac{1}{i}\) 。要想求解它,我们需要了解一下调和级数
定义
性质
- 发散性,即:
 
- 渐近性,即:
 
- 其中
 
整除分块(数论分块)
问题引入
考虑计算下面的式子:
直接计算该式可扫描 \(1\sim n\) ,时间复杂度为 \(\mathcal{O}(n)\) ,但通过观察 \(\left\lfloor\frac{n}{i}\right\rfloor\) 值的分布,发现有许多连续区间值相同,例如:
当 \(n = 10\) 时:
| \(i\) | \(1\) | \(2\) | \(3\) | \(4\) | \(5\) | \(6\) | \(\cdots\) | \(10\) | 
|---|---|---|---|---|---|---|---|---|
| \(\left\lfloor\frac{n}{i}\right\rfloor\) | \(10\) | \(5\) | \(3\) | \(2\) | \(2\) | \(1\) | \(\cdots\) | \(1\) | 
其中 \(i\in[4,5]\) 的值都为 \(2\) , \(i\in[6,10]\) 的值都为 \(1\) ,这些连续区间可以合并后再进行计算来减少时间复杂度。
定义
设正整数 \(n\) ,将区间 \([1,n]\) 划分为 \(m\) 个连续子区间:
满足:
- 连续性: \(j_k + 1 = i_{k + 1}\ \left(1\le k<m\right)\) 。
 - 同值性: \(\forall x\in[i_k,j_k],\left\lfloor\frac{n}{x}\right\rfloor=c_k\) 。
 - 递减性: \(\forall k,\ c_{k-1}>c_k\ \left(k >1\right)\) 。
 
符号说明:
- \(i_k,j_k\) 分别表示第 \(k\) 个块的起点和终点。
 - \(c_k\) :块内所有 \(x\) 的整除值 \(\left\lfloor\frac{n}{x}\right\rfloor\) 。
 
性质
- 连续性
 - 同值性
 - 递减性
 - 利用整除分块分块,总块数不会超过 \(2\sqrt{n}\) 块。
 
证明:
前面已知 \(n\) 的约数最多有 \(2\sqrt{n}\) 个,并且成对在 \(\sqrt{n}\) 左右分布(完全平方数除外),所以我们可以进行分类讨论:
- 当 \(x\in[1,\sqrt{n}]\) 时:\(n\) 至多有 \(\sqrt{n}\) 个约数,即 \(\left\lfloor\frac{n}{x}\right\rfloor\) 的值至多有 \(\sqrt{n}\) 种 ,所以至多分为 \(\sqrt{n}\) 个块。
 - 当 \(x\in(1, \sqrt{n}]\) 时: \(\left\lfloor\frac{n}{x}\right\rfloor\le\frac{n}{x}<\frac{n}{\sqrt{n}}=\sqrt{n}\) ,即 \(\left\lfloor\frac{n}{x}\right\rfloor\in[1,\sqrt{n})\) ,所以至多分为 \(\sqrt{n}\) 个块。
 所以总共至多分为 \(2\sqrt{n}\) 个块。
证毕
算法流程
考虑到块的数量至多有 \(2\sqrt{n}\) 个,我们尝试对每一个块进行遍历。
首先设每个块的左端点为 \(L\) ,右端点为 \(R\) (即满足 \(\left\lfloor\frac{n}{i}\right\rfloor=\left\lfloor\frac{n}{L}\right\rfloor\) 最大的 \(i\) ),每次将 \(L\) 赋值为 \(R + 1\) 即可跳到下一个块。
显然 \(L\) 的初值为 \(1\) ,但 \(R\) 就有些复杂了。
设 \(k = \left\lfloor\frac{n}{L}\right\rfloor\) ,即 \(\left\lfloor\frac{n}{L}\right\rfloor=\left\lfloor\frac{n}{R}\right\rfloor=k\) 。
既然 \(\left\lfloor\frac{n}{R}\right\rfloor = k\) ,是否 \(\left\lfloor\frac{n}{k}\right\rfloor = R\) 呢?直觉告诉我们这是正确的,我们先顺这这个思路往下推。
注意到 \(k = \left\lfloor\frac{n}{L}\right\rfloor\) ,所以 \(R=\left\lfloor\frac{n}{k}\right\rfloor=\left\lfloor\dfrac{{n}}{\left\lfloor\frac{n}{L}\right\rfloor}\right\rfloor\) 。
接下来就是当 \(\left\lfloor\frac{n}{R}\right\rfloor=k\) ,求证 \(\left\lfloor\frac{n}{k}\right\rfloor=R\) 。
即若 \(\left\lfloor\frac{n}{x}\right\rfloor=y\) ,求证: \(\left\lfloor\frac{n}{y}\right\rfloor=x\)
证明:
\[\begin{aligned} &\left\lfloor\frac{n}{x}\right\rfloor=y\\ \Rightarrow\ &y\le\frac{n}{x}<y+1\\ \Rightarrow\ &y\cdot x\le n<(y+1)\cdot x\\ \Rightarrow\ &x\le\frac{n}{y}<x+\frac{x}{y}\\ \end{aligned} \]当 \(x \le y\) 时:
\[\begin{aligned} &x\le y\\ \Rightarrow\ &\frac{x}{y}\le1\\ \Rightarrow\ &x + \frac{x}{y}\le x + 1\\ \Rightarrow\ &x\le\frac{n}{y}<x+1\\ \Rightarrow\ &\left\lfloor\frac{n}{y}\right\rfloor=x \end{aligned} \]当 \(x>y\) 时:
\[\begin{aligned} &\frac{x}{y}<1\\ \Rightarrow\ &x + \frac{x}{y}>x+1 \end{aligned} \]此时无法保证 \(\dfrac{n}{y} < x + 1\) ,可能存在反例。
综上所述:\[\boxed{\left\lfloor\frac{n}{x}\right\rfloor=y\land x\le y\Rightarrow\left\lfloor\frac{n}{y}\right\rfloor=x} \]证毕
此时发现,结论中多了一组 \(x\le y\) 的前提条件,所以我们需要证明一下 \(R\le\left\lfloor\dfrac{n}{L}\right\rfloor\) 。
证明:
已知 \(\left\lfloor\frac{n}{R}\right\rfloor=k\) ,则 \(n=k\times R+r\) ,若 \(r \ge k\) , \(n\) 就可以表示为 \(k\times(R + 1)+r-k\) ,所以 \(R\) 就可以 \(R + 1\) 代替,与 \(R\) 的定义不符。证毕
代码
int solve(int n) {
	int res = 0;
	for (int l = 1, r; l <= n; l = r + 1) {
		r = n / (n / l);
		ans += (n / l) * (r - l + 1);
	}
	return res;
}
最大公约数(与最小公倍数)
定义
对于两个自然数 \(a\) 和 \(b\) ,若存在一个最大的自然数 \(d\) ,使得 \(d\ |\ a\) 且 \(d\ |\ b\) ,则称 \(d\) 为 \(a,b\) 的最大公约数,记为 \(\gcd(a,b)\) 。
对于两个自然数 \(a\) 和 \(b\) ,若存在一个最小的自然数 \(m\) ,使得 \(a\ |\ m\) 且 \(b\ |\ m\) ,则称 \(d\) 为 \(a,b\) 的最小公倍数,记为 \(\text{lcm}(a,b)\) 。
定理
证明:
设 \(d=\gcd(a,b),\ a_0=\dfrac{a}{d},\ b_0=\dfrac{b}{d}\) 。根据最大公约数的定义有 \(\gcd(a_0,b_0)=1\) ,根据最小公倍数的定义有 \(\text{lcm}(a_0,b_0)=a_0\times b_0\) 。
所以 \(\text{lcm}(a,b)=\text{lcm}(a_0\times d,b_0\times d) = \text{lcm}(a_0,b_0)\times d=a_0\times b_0\times d=\dfrac{a\times b}{d}\) ,即 \(\gcd(a,b)\times\text{lcm}(a,b)=a\times b\)证毕
九章算术 · 更相减损术
证明:
根据最大公约数的定义,后者显然成立,我们主要证明前者。
设 \(a=k_1\times d,b=k_2\times d\) ,则 \(a-b=(k_1-k_2)\times d\) ,所以 \(d\ |\ (a-b)\) 。因此 \(d\) 也是 \(b,a-b\) 的公约数。反之亦然成立。故 \(a,b\) 的公约数集合与 \(b,a-b\) 的公约数集合相同。于是它们的最大公约数自然也相等。对于 \(a,a-b\) 同理。证毕
欧几里得算法 · 辗转相除法
证明:
若 \(a < b\) ,则 \(\gcd(b,a\bmod b)=\gcd(b,a)=\gcd(a,b)\) ,命题成立。
若 \(a \ge b\) ,设 \(d\) 为 \(a, b\) 任意公约数, \(a=k\times b+r\) ,则 \(r=a-k\times b=a\bmod b\) 。
因为 \(d\ |\ a, d\ |\ (k\times b)\) ,所以 \(d\ |\ (a - k\times b)\) ,即 \(d\ |\ r\) 。反之亦然成立。故 \(a,b\) 公约数集合与 \(b,a\bmod b\) 的公约数集合相同。于是它们的最大公约数自然也相等。证毕
由 \(a\bmod b<\dfrac{a}{2}(a\ge b)\) 的取模性质(证明详见这篇题解中对取模性质 \(2\) 的证明部分)可得出使用欧几里得算法求最大公约数的复杂度为为 \(\mathcal{O}\left(\log\left(a + b\right)\right)\) ,因此欧几里得算法是最常用的求最大公约数的方法。不过,因为高精度除法(取模)不容易实现,需要做高精度运算时,可考虑用更相减损术代替欧几里得算法。
代码
int gcd(int a, int b) {
	return b ? gcd(b, a % b) : a;
}
互质与欧拉函数
互质
定义
欧拉函数
定义
\(1\sim n\) 中与 \(n\) 互质的数的个数被称为欧拉函数,记为 \(\varphi(n)\) 。
形式化地:
求法 \(1\sim 2\)
\(1\) : \(\mathcal{O}(n\log n)\) 求法
最暴力的算法,从 \(1\sim n\) 挨个判断,时间复杂度为 \(\mathcal{O}(n\log n)\) 。
\(2\) : \(\mathcal{O}(n√n)\) 求法
显然我们需要一些更优秀的做法。
假如 \(n\) 只有 \(p\) 一个质因子,那么 \(1\sim n\) 中与 \(n\) 不互质的只能是 \(p\) 的倍数,显然 \(\varphi(n)=n-\dfrac{n}{p}\) 。
假如 \(n\) 还有一个质因子 \(q\) ,那么 \(1\sim n\) 中与 \(n\) 不互质的只能是 \(p\) 的倍数或 \(q\) 的倍数,即 \(n-\dfrac{n}{p}-\dfrac{n}{q}\) ,但由于有的数既是 \(p\) 的倍数,也是 \(q\) 的倍数,所以我们要把多减的部分加回来即:
推广到一般情况可得到:
特别地,\(\varphi(1)=1\) 。
这样 \(\varphi(n)\) 可以用质因数分解 \(\mathcal{O}(\sqrt{n})\) 求出。
所以总的时间复杂度为 \(\mathcal{O}(n\sqrt n)\) 。
代码
int phi(int n) {
	int res = n;
	if (n == 1) return 1;
	for (int i = 2; i <= n; i++) {
		if (!(n % i)) continue;
		res = res / i * (i - 1);
		while (!(n % i)) n /= i;
	}
	return res;
}
性质
- 
\(\forall n > 1,1\sim n\) 中与 \(n\) 互质的数的和为 \(\dfrac{n\times\varphi(n)}{2}\) ,即 \(\sum\limits_{i=1}^ni\times[n\perp i]=\dfrac{n\times\varphi(n)}{2}\)
证明:
对于任意 \(\forall i\in[1,n]\) ,有 \(\gcd(n,i)=1\) ,由更相减损术知 \(\gcd(n,n-i)=1\) 。
所以说在 \([1,n]\) 内,与 \(n\) 互质的数字是成对出现的, 由于我们只关心最后的和,所以我们可以通过计算它们的平均数来求和。
不难发现,它们的平均数 \(\dfrac{i+n-i}{2}=\dfrac{n}{2}\) 为定值,所以这些数字之和为 \(\dfrac{n\times\varphi(n)}{2}\) 。证毕
 - 
\(\varphi(n)\) 是积性函数。
- 定义:
- 积性函数:若 \(a\perp b\) ,则 \(f(a)\times f(b)=f(a\times b)\)
 - 完全积性函数:对于 \(\forall a,b\in\mathbb{N}_+,f(a)\times f(b)=f(a\times b)\)
 
 - 性质:
- 对 \(n\) 进行唯一分解, \(n=\prod\limits_{i=1}^mp_i^{c_i}\) ,则有 \(f(n)=\prod\limits_{i=1}^mf(p_i^{c_i})\) 。
 
 
证明:
由于 \(a\perp b\) ,所以 \(a,b\) 没有共同的质因子。
对 \(a,b,a\times b\) 唯一分解得: \(a=\prod\limits_{i=1}^{m_1}p_i^{c_i},b=\prod\limits_{i=1}^{m_2}q_i^{d_i},a\times b=\left(\prod\limits_{i=1}^{m_1}p_i^{c_i}\right)\times\left(\prod\limits_{i=1}^{m_2}q_i^{d_i}\right)\) 。
则 \(\varphi(a)\times\varphi(b)=a\times b\times\prod\limits_{i=1}^{m_1}\left(\frac{p_i-1}{p_i}\right)\times \prod\limits_{i=1}^{m_2}\left(\frac{q_i-1}{q_i}\right)=\varphi(a\times b)\) 。证毕
 - 定义:
 - 
设 \(n=p^k\) ( \(p\) 是质数),则 \(\varphi(n)=p^k-p^{k-1}=p^{k-1}\times(p-1)\) 。
证明:
易知 \(n\) 只有 \(p\) 一个质因子,所以 \(1\sim n\) 之间与 \(n\) 不互质的数必是 \(p\) 的倍数, 因此这样的数共有 \(\dfrac{n}{p}=\dfrac{p^k}{p}=p^{k-1}\) 个。
由此可得 \(\varphi(n)=n-p^{k-1}=p^k-p^{k-1}=p^{k-1}\times(p-1)\) 。证毕
 - 
若 \(p\) 为质数且 \(p\mid n\) ,则 \(\varphi(p\times n) = p\times\varphi(n)\) 。
证明:
因为 \(p\mid n\) ,所以它们的质因子集合显然相同。
因此 \(\varphi(p\times n) = p\times n\times\prod\limits_{i=1}^m\left(1-\frac{1}{p_i}\right) = p\times\varphi(n)\) 。证毕
 - 
若 \(p\) 为质数且 \(p\nmid n\) ,则 \(\varphi(p\times n)=(p-1)\times\varphi(n)\) 。
证明 \(1\) :
对 \(n,p\times n\) 唯一分解得: \(n=\prod\limits_{i=1}^mq_i,p\times n=\prod\limits_{i=1}^mq_i\times p\) 。
同性质 \(4\) 类似, \(\varphi(p\times n)=p\times n\times\prod\limits_{i=1}^m\left(\frac{q_i-1}{q_i}\right)\times \frac{p-1}{p}=(p-1)\times\varphi(n)\) 。证毕
证明 \(2\) :
因为 \(p\) 为质数且 \(p\nmid n\) ,所以 \(p\perp n\) ,因此我们巧用 \(\varphi(n)\) 为积性函数的性质,则 \(\varphi(p\times n)=\varphi(p)\times \varphi(n)\) 。
又因为 \(p\) 是质数,所以 \(\varphi(p)=p-1\) 。即 \(\varphi(p)\times\varphi(n)=(p-1)\times \varphi(n)\) 。证毕
 - 
\(\sum\limits_{d\mid n}^k\varphi(d)=n\) ,也就是 \(n\) 的所有约数的欧拉数值之和为 \(n\) 。
证明:
设 \(f(n)=\sum\limits_{d\mid n}\varphi(d)\) ,且 \(n\perp m\) ,所以 \(n\) 和 \(m\) 没有相同的质因子,即下式中的 \(d_1\mid n\) 与 \(d_2\mid m\) 是互相独立的。\[ \begin{aligned} f(n)\times f(m)&=\left(\sum\limits_{d\mid n}\varphi(d)\right)\times\left(\sum\limits_{d\mid m}\varphi(d)\right)\\ &=\sum\limits_{d_1\mid n}\sum\limits_{d_2\mid m}\varphi(d_1)\varphi(d_2)\\ &=\sum\limits_{d_1\mid n}\sum\limits_{d_2\mid m}\varphi(d_1d_2)\\ &=\sum_{d\mid nm}\varphi(d)\\ &= f(nm) \end{aligned} \]即 \(f(n)\) 为积性函数,所以 \(f(n)=\prod\limits_{i=1}^mf(p_i^{c_i})\) ,我们再利用性质 \(3\) 分解 \(f(p_i^{c_i})\) :
\[ \begin{aligned} f(p_i^{c_i})&=\sum_{j=0}^{c_i}\varphi(p_i^j)\\ &=1 + \sum_{j=1}^{c_i}(p^j-p^{j-1})\\ &=1 + p-1+p^2-p+\cdots+p^{c_i}-p^{c_i-1}\\ &=1-1+p-p+p^2-p^2+\cdots+p^{c_{i-1}}-p^{c_{i-1}}+p^{c_i}\\ &=p^{c_i} \end{aligned} \]所以 \(f(n)=\prod\limits_{i=1}^mf(p_i^{c_i})=\prod\limits_{i=1}^mp_i^{c_i}=n\) ,即 \(\sum\limits_{d\mid n}\varphi(d)=n\) 。
证毕
 
求法 \(3\) (线性求法)
根据性质 \(4\) 和性质 \(5\) 对 \(\text{Euler}\) 筛法进行一点小修改即可,总的时间复杂度为 \(\mathcal{O}(n)\) 。
代码
void euler(int n) {
	phi[1] = 1;
	for (int i = 2; i <= n; i++) {
		if (!isp[i]) {
			p[++p[0]] = i;
			phi[i] = i - 1;
		}
		for (int j = 1; j <= p[0] && i * p[j] <= n; j++) {
			isp[i * p[j]] = 1;
			if (i % p[j] == 0) {
				phi[i * p[j]] = phi[i] * p[j];
				break;
			} else phi[i * p[j]] = phi[i] * (p[j] - 1);
		}
	}
}

                
            
        
浙公网安备 33010602011771号