数学知识(一)

温馨提示:本篇含有大量 \(\LaTeX\) 公式,可能加载较慢!

一. 质数

定义

若一个正整数的因数只有 \(1\) 和它本身,那么这个数就是质数,否则为合数。特殊的,\(1\) 既不是质数,又不是合数。

质数分布定理

\[\lim\limits_{n\rightarrow \infty}\pi(n) = \frac{n}{\ln n} \]

用人话来说就是当 \(n\) 趋近正无穷时,不超过 \(n\) 的质数大约有 \(\frac{n}{\ln n}\) 个。

质数的判定

如何判定一个正整数 \(n\) 是不是质数?

试除法

从定义出发,枚举 \(2\sim \lfloor\sqrt n\rfloor\) 的整数,一个一个试能不能整除。若能则为合数,否则为质数。

\(\texttt{Code:}\)

bool check(int n) {
    if(n < 2) return false;
    for(int i = 2; i <= n / i; i++)
        if(n % i == 0) return false;
    return true;
}

分解质因数

算数基本定理

内容:

任何一个大于 \(1\) 正整数都能唯一分解成有限个质数的乘积,可写作:

\[x = p_{1}^{\alpha_1}\times p_{2}^{\alpha_2}\times\cdots\times p_{k}^{\alpha_n} \]

在分解质因数时也可以用试除法,枚举 \(2\sim \lfloor\sqrt n\rfloor\) 的整数,若找到了一个能整除的数,就把它从 \(n\) 中除尽,这样就能保证后面满足这个条件的数一定是质数,就不用额外判断是不是质数了。

\(\texttt{Code:}\)

for(int i = 2; i <= n / i; i++) {
    int s = 0;
    while(n % i == 0) n /= i, s++; //除尽
    if(s > 0) printf("%d %d\n", i, s);
}
if(n > 1) printf("%d %d\n", n, 1); //可能会剩下一个比较大的质因子

质数筛

1. 埃氏筛

思路:

把找到的质数的所有不大于 \(\sqrt n\) 的倍数全都筛掉,剩下的就全是质数了。
但是,同一个数会被它的不同质因子都筛一遍,效率有所降低。

时间复杂度:\(O(n\log\log n)\)

代码:

void ai(int n) {
	for(int i = 2; i <= n; i++) {
		if(!st[i]) {
			primes[++tt] = i;
			for(int j = 2; i * j <= n; i++) st[i * j] = true;
		}
	}
}

2. 欧拉筛(线性筛)

思路:

在埃氏筛的基础上进行了优化,保证每个合数只会被它的最小质因子筛掉,时间复杂度有所降低。

时间复杂度:\(O(n)\)

代码:

void ol(int n) {
	for(int i = 2; i <= n; i++) {
		if(!st[i]) primes[++tt] = i;
		for(int j = 1; j <= tt && i * primes[j] <= n; j++) {
			st[i * primes[j]] = true; 
			if(i % primes[j] == 0) break; //确保primes[j]一定是i的最小质因子,则primes[j]一定也是i * primes[j]的最小质因子,这样就确保了每个合数只会被它的最小质因子筛掉 
		}
	}
}

二. 因数

对于一个数 \(x(x \in [2,+\infty))\),可以写成如下形式:

\[x = p_{1}^{\alpha_1}\times p_{2}^{\alpha_2}\times\cdots\times p_{k}^{\alpha_n} \]

对于每一个因数 \(d\),都可写成:

\[d = p_{1}^{\beta_1}\times p_{2}^{\beta_2}\times\cdots\times p_{k}^{\beta_n} \]

由排列组合知识可知,\(x\) 的约数个数 \(num(x)\) 为:

\[(\alpha_1 + 1)\times(\alpha_2 + 1)\times\cdots\times(\alpha_k + 1) \]

约数之和 \(sum(x)\) 为:

\[(p_{1}^0+p_{1}^1+p_{1}^2+ \cdots +p_{1}^{\alpha_1})\times (p_{2}^0+p_{2}^1+p_{2}^2+\cdots+p_{2}^{\alpha_2})\cdots\times (p_{k}^0+p_{k}^1+p_{k}^2+ \cdots +p_{k}^{\alpha_k}) \]

根据等比数列求和公式可得:

\[sum(x) = \prod\limits_{i = 1}^k\frac{p_i^{\alpha_i + 1} - 1}{p_i - 1} \]

试除法分解因数

因为一个数 \(n\) 的因数个数为 \(O(\sqrt n)\),所以时间复杂度为 \(O(\sqrt n)\)

\(\texttt{Code:}\)

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

int n;

vector <int> get(int x) {
    vector <int> res;
    for(int i = 1; i <= x / i; i++) {
        if(x % i == 0) {
            res.push_back(i);
            if(i != x / i) res.push_back(x / i);
        }
    }
    sort(res.begin(), res.end());
    return res;
}

int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        int x;
        scanf("%d", &x);
        vector <int> ans = get(x);
        for(auto i : ans) printf("%d ", i);
        puts("");
    }
    
    return 0;
}

最大公因数

定义:

\(d \mid a\)\(d \mid b\),则 \(d\)\(a,b\) 的公因数,其中满足条件的最大的 \(d\) 就是最大公因数,记为 \(\gcd(a, b)\)

最小公倍数

定义:

\(a \mid m\)\(b \mid m\),则 \(m\)\(a,b\) 的公倍数,其中满足条件的最小的 \(m\) 就是最小公倍数,记为 \(\operatorname{lcm}(a, b)\)

几个有意思的定理

  1. \(\gcd(a, b)\cdot \operatorname{lcm}(a, b) = a\cdot b\)

  2. \(a,b\) 的所有公因数都是最大公因数的因数,所有公倍数都是最小公倍数的倍数。

证明:

考虑将 \(a,b\) 分解质因数,并将质因数对齐,得:

\[a = p_{1}^{a_1}p_{2}^{a_2}\cdots p_{k}^{a_k} \]

\[b = p_{1}^{b_1}p_{2}^{b_2}\cdots p_{k}^{b_k} \]

再将 \(\gcd(a, b) = fac\)\(\operatorname{lcm}(a, b) = m\) 分解质因数,得:

\[fac = p_{1}^{c_1}p_{2}^{c_2}\cdots p_{k}^{c_k} \]

\[m = p_{1}^{d_1}p_{2}^{d_2}\cdots p_{k}^{d_k} \]

注意!这里的 \(a_i,b_i,c_i,d_i\) 可能为 \(0\)!(因为可能不含此质因子)

根据定义可知:

\[c_i = \min(a_i, b_i),d_i = max(a_i, b_i),i\in [1, k] \]

对于每个质因子 \(p_i\) 来看,\(d\)\(m\) 相乘即为:

\[p_i^{\min(a_i, b_i)}\cdot p_i^{\max(a_i, b_i)} = p_i^{a_i + b_i} \]

所以总的乘起来就是 \(a\cdot b\)

证明完毕。

\(2\) 的话顺着这个继续证,很容易就证出来了。

\(1\) 可知,只用知道其中一种的计算方法就可以直接推出另一种,所以只用考虑 \(\gcd\) 该怎么计算。

若直接朴素计算 \(\gcd\),最先想到的方式就是分解出其中一个数的所有因数,然后找最大的且能整除另一个数的因子,时间复杂度 \(O(\sqrt n)\)

还有更快的方法吗?

九章算术 · 更相减损术

内容:

\[\forall a, b\in \mathbb{N},a\ge b,\text{有} \gcd(a, b) = \gcd(b, a - b) = \gcd(a, a - b) \]

证明:

对于 \(a,b\) 的任意公因数 \(d\),由于 \(d \mid a,d \mid b\),所以 \(d \mid (a - b)\)。因此,\(d\) 也是 \(b, a - b\) 的公因数。所以 \(a,b\) 的公因数集合与 \(b, a - b\) 的公因数集合相同,那么最大公因数自然也就相同。对与 \(a,a - b\) 同理。

证明完毕。

这种方法当 \(a,b\) 相差不大时效率较高,但差距一旦过大,一直减也减不完,效率大打折扣。

但是这个方法可以扩展到 \(n\) 个数,即:

\[\gcd(a_1, a_2,\cdots ,a_n) = \gcd(a_1, a_2 - a_1, a_3 - a_2,\cdots ,a_n - a_{n - 1}) \]

欧几里得算法

我们发现上一种方法一次一次地减效率太低了,干脆一次就减完,即取模。

欧几里得算法就是在这个方面进行了优化。

内容:

\[\forall a, b\in \mathbb{N},b \ne 0, \gcd(a, b) = \gcd(b, a \bmod b) \]

证明:

和上一种方法如出一辙。

\(a < b\),则上式显然成立。

\(a\ge b\),不妨设 \(a = k\cdot b + r\),其中 \(0\le r < b\)。显然 \(r = a \bmod b\)

对于 \(a,b\) 的任意公约数 \(d\),由于 \(d \mid a,d \mid (k\cdot b)\),所以 \(d \mid (a - k\cdot b)\),即 \(d \mid r\)。因此 \(d\) 也是 \(b,r\) 的公因数。所以 \(a,b\) 的公因数集合和 \(b,a\bmod b\) 的公因数集合相同,最大公约数自然也就相等了。

证明完毕。

每次我们将 \(\gcd(a, b)\) 变成了 \(\gcd(b, a\bmod b)\),分析一下括号里两个变量的变化。

  1. \(a < b\) 时,\(\gcd(a, b)\rightarrow \gcd(b, a)\),就变成下面情况 \(2\)\(3\)

  2. \(b\le a < 2b\) 时,\(\gcd(a, b) = \gcd(b, a - b)\) 进一步分析就会发现,括号中的第二个元素至少减少了一半。

  3. \(a\ge 2b\),括号中的第二个元素 \(b\rightarrow a\bmod b\) 一定小于 \(b\) 也至少减少了一半。

综上所述,每次迭代第二个元素都会至少减半,所以时间复杂度是 \(\log\) 级别的。具体的,时间复杂度应该是 \(O(\log\max(a, b))\)

一般的,对于多个数 \(a_1,a_2,\cdots, a_n\),做欧几里得算法的时间复杂度为 \(O(n + \log\max\limits_{1\le i\le n}\{a_i\})\)

直接上代码:

int gcd(int x, int y) { //最大公因数
	if(y == 0) return  x;
	return gcd(y, x % y);
}

int lcm(int x, int y) { //最小公倍数
	return x * y / gcd(x, y);
}

欧拉函数

定义:

欧拉函数就是指对于 \(m\) 来讲,在 \(1 \sim m\) 中与 \(m\) 互素的数的个数,例如,当 \(n = 8\) 时,与 \(8\) 互质的数分别是 \(1,3,5,7\),因此 \(\varphi(8) = 4\)

对于 \(\{p_n\}\),\(\{\alpha_n\}\), \(m\in N_{\pm}\) 来讲,满足 \(m=\textstyle \prod\limits_{1\leq j\leq n}^{n}p_{j}^{\alpha_{j}}\) (即 \({p_{n}}\) 为其质因子)

\(\varphi(m)=m\cdot\prod\limits_{1\leq j\leq n}^{n}\left(1-\textstyle{\frac{1}{p_j}}\right).\)

证明在这里

套公式代码:(时间复杂度:\(O(\sqrt n)\)

#include <iostream>
using namespace std;
int n;
int main() {
    scanf("%d", &n);
    while(n--) {
        int x;
        scanf("%d", &x);
        
        int res = x;
        for(int i = 2; i <= x / i; i++) { //分解质因数
            if(x % i == 0) {
                res = res / i * (i - 1);
                while(x % i == 0) x /= i;
            }
        }
        if(x > 1) res = res / x * (x - 1);
        
        printf("%d\n", res);
    }
    return 0; //直接套公式也没什么好说的
}

若要求 \(1\sim n\) 中所有数的欧拉函数,一个一个求的时间复杂度为 \(O(n\sqrt n)\),效率较低。

其实可以在线性筛质数时顺便求欧拉函数。

首先需要了解积性函数。

定义:

\(a, b\) 互质且有 \(f(ab) = f(a)\cdot f(b)\),则称 \(f\) 是积性函数。

基本性质:

\(f\) 是积性函数,则 \(n = \prod\limits_{i = 1}^m p_i^{c_i}\),则 \(f(n) = \prod\limits_{i = 1}^m f(p_i^{c_i})\)

证明:

\(n\) 分解质因数,对每个质因子都使用积性函数的定义,此性质显然成立。

接着我们需要欧拉函数的几个性质:

  1. 欧拉函数是积性函数。

  2. \(p\) 为质数,若 \(p \mid n\)\(p^2 \mid n\),则 \(\varphi(n) = \varphi(n / p) * p\)

  3. \(p\) 为质数,若 \(p \mid n\)\(p^2 \nmid n\),则 \(\varphi(n) = \varphi(n / p) * (p - 1)\)

证明:

性质 \(1\)

要证欧拉函数是积性函数,即证:有 \(a, b\) 互质且有 \(\varphi(ab) = \varphi(a)\cdot \varphi(b)\)

因为 \(\gcd(a, b) = 1\),所以 \(a, b\) 的质因数一定没有一个相同,将 \(a,b\) 分解质因数。

\[a = p_1^{c_1}p_2^{c_2}\cdots p_k^{c_k} \]

\[b = q_1^{d_1}q_2^{d_2}\cdots q_m^{d_m} \]

\[\varphi(a) = a\cdot (1 - \frac{1}{p_1})(1 - \frac{1}{p_2})\cdots (1 - \frac{1}{p_k}) \]

\[\varphi(b) = b\cdot (1 - \frac{1}{q_1})(1 - \frac{1}{q_2})\cdots (1 - \frac{1}{q_m}) \]

\[\varphi(ab) = (ab)\cdot [(1 - \frac{1}{p_1})(1 - \frac{1}{p_2})\cdots (1 - \frac{1}{p_k})]\cdot [(1 - \frac{1}{q_1})(1 - \frac{1}{q_2})\cdots (1 - \frac{1}{q_m})] \]

\(\therefore\varphi(ab) = \varphi(a)\cdot \varphi(b)\)

性质 \(1\) 得证。

性质 \(2\)

\(p \mid n\)\(p^2 \mid n\),则 \(n,n / p\) 拥有相同的质因子,只是指数不同罢了,但是欧拉函数的计算只看有没有这个质因子而不关心指数。设 \(n,n / p\) 的质因子都为 \(p_1, p_2,\cdots ,p_k\),则

\[\varphi(n) = n\cdot (1 - \frac{1}{p_1})(1 - \frac{1}{p_2})\cdots (1 - \frac{1}{p_k}) \]

\[\varphi(n / p) = (n / p)\cdot (1 - \frac{1}{p_1})(1 - \frac{1}{p_2})\cdots (1 - \frac{1}{p_k}) \]

两者相除,商为 \(p\)
性质 \(2\) 得证。

性质 \(3\)

\(p \mid n\)\(p^2 \nmid n\),则 \(n,n / p\) 互质,根据性质 \(1\) 可得 \(\varphi(n) = \varphi(n / p) * \varphi(p)\),而 \(\varphi(p) = p - 1\),所以 \(\varphi(n) = \varphi(n / p) * (p - 1)\)

性质 \(3\) 得证。

综上所述,我们可以把上述性质与线性筛法结合起来。

具体地,每个合数 \(x\) 只会被它的最小质因子 \(p\) 筛一次,恰好在此时判断,从 \(\varphi(x / p)\) 递推到 \(\varphi(n)\)

时间复杂度为 \(O(n)\)

void get_eulers() {
    phi[1] = 1;
    for(int i = 2; i <= n; i++) {
        if(!st[i]) {
            prime[++cnt] = i;
            phi[i] = i - 1; //若是质数就直接求出欧拉函数
        }
        for(int j = 1; j <= cnt && prime[j] <= n / i; j++) {
            st[i * prime[j]] = true;
            if(i % prime[j] == 0) {
                phi[i * prime[j]] = phi[i] * prime[j]; //此时 primes[j] 是 i 的最小质因子,即此时满足性质 2
                break;
            }
            phi[i * prime[j]] = phi[i] * (prime[j] - 1); //否则满足性质 3
        }
    }
}

三. 同余

概念:

数学上,同余(\(\texttt{congruence modulo}\),符号: \(\equiv\)) 是数论中的一种等价关系。当两个整数除以同一个正整数,若得相同余数,则两个整数同余。

同余运算的常见性质

  1. \(a\equiv b\pmod p \Longleftrightarrow p \mid (a - b)\)

  2. \(a\equiv b\pmod m,a\equiv b\pmod n\Rightarrow a\equiv b\pmod {[m, n]}\)

  3. \((k, m) = d, ka\equiv kb\pmod m\Rightarrow a\equiv b\pmod {\frac{m}{d}}\)

证明:

对于性质 \(1\)

根据定义,设 \(a = k_1p + r,b = k_2p + r\),所以 \(a - b = (k_1 - k_2)p\),所以 \(p \mid (a - b)\)

证毕。

对于性质 \(2\)

根据性质 \(1\) 得:\(n \mid (a - b),m \mid (a - b)\),所以 \([m, n] \mid (a - b)\),即 \(a\equiv b\pmod {[m, n]}\)

证毕。

对于性质 \(3\)

根据性质 \(1\) 得:\(m \mid k(a - b)\),因为 \(\gcd(k, m) = d\),所以 \(\frac{m}{d} \mid \frac{k}{d}(a - b)\),又因为 \(\gcd(\frac{m}{d},\frac{k}{d}) = 1\),所以 \(\frac{m}{d} \mid (a - b)\),即\(a\equiv b\pmod {\frac{m}{d}}\)

证毕。

基本知识 —— 关于 \(\bmod\)

  • 同余类/剩余类

由对于模 \(n\) 同余的所有整数组成的这个集合称为同余类\(\texttt{congruence class}\)\(\texttt{residue class}\)),或称剩余类

可知,模 \(n\) 的同余类一共有 \(n\) 个,分别是模 \(n\equiv 0,1,\cdots n - 1\) 的这 \(n\) 个。

如果模 \(m\) 的一个剩余类里所有数都与 \(m\) 互素,就把它叫做与模 \(m\) 互素的剩余类,比如: \(5\) 的一个剩余系为 \(\{4, 9, 14, \cdots ,5k+4(k \in \mathbb{Z})\}\),其中所有数都与 \(5\) 互素,所以此剩余系是与 \(5\) 互素的剩余系。

  • 完全剩余系:

从模 \(n\)每个剩余类中各取一个数,得到一个由 \(n\) 个数组成的集合,叫做模 \(n\) 的一个完全剩余系,简称完系

显然,完系中的 \(n\) 个数分别属于 \(n\) 个不同的剩余类。比如 \(\{0,1,2,3,4\}\)\(5\) 的一个完系,\(\{5,6,7,8,9\}\) 也是 \(5\) 的一个完系。

  • 最小非负完全剩余系

最简单的模 \(n\) 的完全剩余系是 \(\{1,2,3,\cdots,n-1\}\) 也叫作模 \(n\)最小非负完系

  • 简化剩余系

简化剩余系( \(\texttt{reduced residue system}\) ) 也称既约剩余系缩系在与模 \(m\) 互素的全体剩余类中,从每一个类中各任取一个数作为代表组成的集合,叫做模 \(m\) 的一个简化剩余系

有无穷多个简化剩余系。例如,模 \(5\) 的一个简化剩余系是 \(\{1,2,3,4\}\),模 \(10\) 的一个简化剩余系是 \(\{1,3,7,9\}\),模 \(18\) 的一个简化剩余系是 \(\{1,5,7,11,13,17\}\)

\(m\) 的完全剩余系中与 \(m\) 互素的数构成的子集也是缩系。

此时欧拉函数的真正定义才浮出水面:

欧拉函数( \(\texttt{Euler's totient function}\) )是对于任意正整数其最小非负完系的个数,用 \({\varphi}()\) 来表示,即 当我们用
\(\{a_1,a_2,\cdots,a_n\}\) 来表示模 \(n\) 的最小非负完系时,显然 \(\forall j,s\in N_{+},j \leq s,\gcd(x_{j},m)=1\) 是成立的。而 \(s\) 即表示 \(\{a_n\}\)
的个数,此时

\(\varphi(m) = s\)


费马小定理

内容:

\(p\) 是质数,则对于任意整数 \(a\),有 \(a^{p - 1}\equiv 1\space (\bmod\space n)\)

欧拉定理

内容:

若正整数 \(x, n\),则 \(x^{\varphi(n)}\equiv 1\space (\bmod\space n)\),其中 \(\varphi(n)\) 为欧拉函数。

证明:

\(\{a_1, a_2,\cdots ,a_{\varphi(n)}\}\)\(n\) 的一个缩系,且 \(1\le a_1,a_2,\cdots ,a_{\varphi(n)}\le n\),换句话说,这些数都是 \(1\sim n\) 中与 \(n\) 互质的数,且两两不同。

\(\because\) \(x, n\) 互质。

\(\therefore xa_1, xa_2,\cdots ,xa_{\varphi(n)}\) 也都与 \(n\) 互质,且两两不同。

\(\therefore\) 集合 \(\{xa_1, xa_2,\cdots ,xa_{\varphi(n)}\}\) 和集合 \(\{a_1, a_2,\cdots ,a_{\varphi(n)}\}\) 在模 \(n\) 的条件下完全等价,即:

\[(xa_1)(xa_2)\cdots (xa_{\varphi(n)}) \equiv a_1a_2\cdots a_{\varphi(n)} \]

\[\therefore x^{\varphi(n)}(a_1a_2\cdots a_{\varphi(n)})\equiv a_1a_2\cdots a_{\varphi(n)} \]

这里就要用到一个同余运算的法则了:若 \(ac\equiv bc\space (\bmod\space n)\),且 \(\gcd(c, n) = 1\),那么 \(a\equiv b\)

证明:根据同余的定义,原式可以写成 \(ac - kn = bc - tn\space (k,t\in \mathbb{Z})\),整理得:\((a -b)c = (k - t)n\)

\(\therefore\) \(\text{LHS}\) 需要含有因子 \(n\)

\(\because \gcd(c, n) = 1\)

\(\therefore n \mid (a - b)\)

\(a\equiv b\),证明完毕。

回到原题,由于 \(a_1,a_2,\cdots ,a_{\varphi(n)}\) 都与 \(n\) 互质,所以 \(a_1a_2\cdots a_{\varphi(n)}\) 也与 \(n\) 互质,则可以消掉,得到 \(x^{\varphi(n)}\equiv 1\space (\bmod\space n)\)

\[\texttt{Q.E.D} \]

那么当模数 \(n\) 为质数时,由于 \(\varphi(n) = n - 1\),所以费马小定理就是欧拉定理的一个特殊情况,也能得证。

裴蜀定理

内容:

对于任意整数 \(a,b\),设 \(d = \gcd(a, b)\),则对于所有整数 \(x,y\) 都有 \(d \mid (ax + by)\)。特别的,一定存在一对整数 \(x,y\),满足 \(ax + by = d\)

证明:

第一点是显然的,因为 \(d \mid a,d \mid b\),所以 \(d \mid ax,d \mid by,d \mid (ax + by)\)

对于第二点:

  1. \(b = 0\) 时,显然当 \(x = 1, y = 0\) 时原式成立。

  2. \(b > 0\) 时,则 \(\gcd(a, b) = \gcd(b, a\bmod b)\)。假设存在一对整数 \(x,y\),满足 \(bx + (a\bmod b)y = \gcd(b, a\bmod b)\),因为 \(bx + (a\bmod b)y = bx + (a - b\lfloor\frac{a}{b}\rfloor)y = ay + b(x - \lfloor\frac{a}{b}\rfloor y)\),所以进一步令 \(x' = y, y' = x - \lfloor\frac{a}{b}\rfloor y\),就得到了 \(ax' + by' = \gcd(a, b)\)

接着对欧几里得算法的递归过程使用数学归纳法,可知第二点成立,也就是顺着欧几里得算法递归,最终会把 \(b\) 消成 \(0\)

证明完毕。

P4549 【模板】裴蜀定理

这道题就考察对裴蜀定理的思考深度了。

先看两个数的情况,假如要最小化 \(a_1x_1 + a_2x_2\) 且要为正,根据裴蜀定理,原式的值一定是 \(\gcd(a_1, a_2)\) 的倍数,所以取 \(\gcd(a_1, a_2)\) 是最优的。

推广到 \(3\) 个数的情况,即最小化 \(a_1x_1 + a_2x_2 + a_3x_3\) 且为正,由上可知应最小化 \(\gcd(a_1, a_2) + a_3x_3\),此式子的最小正值应该是 \(\gcd(\gcd(a_1, a_2), a_3) = \gcd(a_1, a_2, a_3)\)

事实上,由于 \(\gcd(\gcd(a_1, a_2,\cdots ,a_{n - 1}), a_n) = \gcd(a_1, a_2,\cdots ,a_n)\),所以是可以直接推广到 \(n\) 个数的,换句话说,原题的答案就是 \(\gcd(a_1, a_2,\cdots ,a_n)\)

同时,裴蜀定理给出了整数 \(x,y\) 的计算方法,所以我们可以在执行欧几里得算法时顺便递归计算,这种计算方法被称为扩展欧几里得算法

\(\texttt{Code:}\)

int exgcd(int a, int b, int &x, int &y) {
    if(b == 0) {x = 1, y = 0; return a;}
    int xx, yy;
    int d = exgcd(b, a % b, xx, yy);
    x = yy;
    y = xx - (a / b) * yy;
    return d;
}

注意 \(x,y\) 是引用传递,上述代码可求出二元一次不定方程 \(ax + by = \gcd(a, b)\) 的一组特解 \(x_0, y_0\),并返回 \(\gcd(a, b)\)

对于更一般的方程 \(ax + by = c\),它有解当且仅当 \(d \mid c\)。所以在有解的情况下,先求出 \(ax + by = \gcd(a, b)\) 的一组特解 \(x_0,y_0\),然后 \(x_0,y_0\) 同乘上 \(\frac{c}{d}\) 即是原方程的一组特解。

那么我们该怎么表示它的通解呢?

\(\gcd(a, b) = d\)。对于 \(ax + by = d\),假设我们已经得到它的一组特解 \(x_0,y_0\),那么我们考虑将 \(x0\) 加上 \(val\) 后得到另一组新整数解 \(x',y'\),所以此时需要满足 \(b \mid (a\cdot val)\) 才行,即 \(val = k\cdot \frac{b}{d},k\in \mathbb{Z}\),此时 \(y\) 应该减少 \(k\cdot \frac{a}{d}\)

综上所述,\(ax + by = d\) 的通解为:

\[x = x_0 + k\cdot \frac{b}{d},\space \space \space \space y = y_0 - k\cdot \frac{a}{d}\space (k\in \mathbb{Z}) \]

推广到一般情况 \(ax + by = c\),通解为:

\[x = \frac{c}{d}x_0 + k\cdot \frac{b}{d},\space \space \space \space y = \frac{c}{d}y_0 + k\cdot \frac{a}{d}\space (k\in \mathbb{Z}) \]

线性同余方程

定义:

形式化定义:形如:\(ax\equiv b\pmod p\) 的式子被称为线性同余方程,也称一次同余方程。

求解

根据同余运算的法则可得:\(p \mid (ax - b)\),即 \(ax + py = b\)。根据裴蜀定理,此方程有解当且仅当 \(\gcd(a, p) \mid b\)

在有解时,先用扩展欧几里得算法求出方程 \(ax + py = \gcd(a, p)\) 的一组特解 \(x_0,y_0\),那么 \(x = \frac{b}{\gcd(a, p)}\cdot x_0\) 就是原方程的一个解,通解则是所有模 \(\frac{p}{\gcd(a, p)}\)\(x\) 同余的整数。

乘法逆元

定义:

若整数 \(b, p\) 互质,并且 \(b \mid a\),则存在一个整数 \(x\),使得 \(\frac{a}{b}\equiv ax\pmod p\)。称 \(x\)\(b\) 的模 \(p\) 乘法逆元,记为 \(b^{-1}\pmod p\)

简单说来,逆元就是人们发现同余运算中有的时候会出现除法,而除法的计算又是比较复杂的,所以就想了一个办法将它转化为乘法,于是逆元应运而生。

因为 \(\frac{a}{b}\equiv ab^{-1}\equiv \frac{a}{b}\cdot b\cdot b^{-1}\),所以 \(b\cdot b^{-1}\equiv 1\pmod p\)

\(p\) 是质数且 \(b < p\) 时,根据费马小定理得:\(b^{p - 1}\equiv 1\),所以 \(b\cdot b^{-1}\equiv b^{p - 1}\),因为 \(b,p\) 互质,所以方程两边同时消去 \(b\),得:

\[b^{-1}\equiv b^{p - 2}\pmod p \]

所以,当模数 \(p\) 为质数时,\(b^{p - 2}\) 即为 \(b\) 的乘法逆元。

意思是若模数时质数,就可以用快速幂来求逆元。

那么如果只保证 \(b,p\) 互质,那么就只能求解方程 \(bx\equiv 1\pmod p\) 得到逆元了。

P3811 【模板】模意义下的乘法逆元

若用上述方法一个一个地求逆元,时间复杂度为 \(O(n\log n)\),在这道题 \(n\le 3\times 10^6\) 的超强数据下会光荣 TLE (其实快速幂加上巴雷特模乘能卡过)

其实要快速求出 \(1\sim n\) 每个数的模 \(p\)\(p\) 为质数)乘法逆元,有一种线性的做法。

\(p = ki + r,0\le r < p\),即 \(p\) 除以 \(i\)\(k\)\(r\)

所以有:

\[p\equiv ki + r\equiv 0\pmod p \]

时刻铭记我们的目标是 \(i^{-1}\),所以得想办法把它创造并分离出来。

两边同乘上 \(i^{-1}\)\(r^{-1}\),得:

\[kr^{-1} + i^{-1}\equiv 0\pmod p \]

\[i^{-1} = -\lfloor\frac{p}{i}\rfloor\cdot (p\bmod i)^{-1}\pmod p \]

特别地,当 \(i = 1\) 时,\(i^{-1} = 1\pmod p\)

然后就可以开始快乐地线性递推了。

\(\texttt{Code:}\)

inv[1] = 1; //注意初始化
for(int i = 2; i <= n; i++)
    inv[i] = p - (p / i) * inv[p % i] % p;

P5431 【模板】模意义下的乘法逆元 2

若要求 \(n\) 个不连续的数的逆元,也要求线性,阁下又该如何应对?

注:以下所有运算都是在 \(\pmod p\) 的情况下进行。

设这 \(n\) 个数分别为 \(a_1,a_2,\cdots ,a_n\)

那么它们的逆元分别为 \(\frac{1}{a_1},\frac{1}{a_2}\cdots ,\frac{1}{a_n}\)

计算这 \(n\) 个数的前缀积 \(sum_1,sum_2,\cdots ,sum_n\)

有递推式:

\[\frac{1}{sum_i} = \frac{1}{sum_{i + 1}}\cdot a_{i + 1} \]

\[\frac{1}{a_i} = \frac{1}{sum_i}\cdot sum_{i - 1} \]

所以我们可以先朴素求出 \(sum_n\) 的逆元,然后从后往前线性递推求出每个 \(sum_i\) 的逆元,进而求出 \(a_i\) 的逆元。

\(\texttt{Code:}\)

    sum[0] = 1;
    for(int i = 1; i <= n; i++) {
        a[i] = read<ll>();
        sum[i] = (sum[i - 1] * a[i]) % p;
    }
    ll x0, y0;
    exgcd(sum[n], p, x0, y0);
    inv_sum[n] = (x0 % p + p) % p;
    for(int i = n - 1; i; i--)
        inv_sum[i] = (inv_sum[i + 1] * a[i + 1]) % p;
    ll tmp = k, res = 0;
    for(int i = 1; i <= n; i++) {
        res = (res + tmp * inv_sum[i] % p * sum[i - 1] % p) % p;
        tmp = tmp * k % p;
    }

中国剩余定理 \(\texttt{(CRT)}\)

内容:

\(m_1,m_2,\cdots ,m_3\) 是两两互质的整数,\(m = \prod\limits_{i = 1}^{n}m_i,M_i = m / m_i,t_i\) 是线性同余方程 \(M_it_i\equiv 1\pmod {m_i}\) 的一个解。对于任意的 \(n\) 个整数 \(a_1,a_2,\cdots ,a_n\),方程组

\[\]

posted @ 2023-12-26 16:36  Brilliant11001  阅读(0)  评论(0编辑  收藏  举报