>
基础数论学习笔记
2022-08-20 学习笔记 约 3.6 千字

整除与约数

约数(因数):若 aba \mid b,则称 bbaa 的倍数,aabb 的约数。

gcd 和 lcm

定义:一组整数的公约数,是指同时是这组数中每一个数的约数的数。11 是任意一组数的公约数,最大公约数(Greatest Common Divisor,gcd\gcd)是指所有公约数里面最大的一个。

性质

  • a,bN\forall a,b \in \mathbb{N},如果 gcd(a,b)=1\gcd(a,b)=1,则称 a,ba, b 互质。

欧几里德算法

114514。

积性函数

素数与合数

void get_primes(int x) {
    memset(notp, 0, sizeof notp);
    for (int i = 2; i <= n; i ++ ) {
        if (!notp[i]) {
            pri[ ++ pcnt] = i;
            for (int j = i; j <= n / i; j ++ ) notp[i * j] = true;
        }
    }
}
void get_primes(int x) {
    memset(notp, 0, sizeof notp);
    notp[1] = true;
    for (int i = 2; i <= x; i ++ ) {
        if (!notp[i]) pri[ ++ pcnt] = i;
        for (int j = 1; i * pri[j] <= x && j <= pcnt; j ++ ) {
            notp[i * pri[j]] = true;
            if (i % pri[j] == 0) break;
        }
    }
}

算术基本定理

欧拉函数

前置知识:

定义:1N1\sim N 中与 NN 互质的数的个数,记为 φ(N)\varphi(N)

性质

  1. pp 为质数,φ(p)=p1\varphi(p)=p-1

证明:质数与 1p11 \sim p-1 中的所有数字都互质。

  1. n>1\forall n>11x1 \sim x 中与 nn 互质的数的和为 n×φ(x)/2n \times \varphi(x)/2

  2. pp 为质数,x=pcx=p^c,则 φ(x)=pc1×(p1)\varphi(x)=p^{c-1} \times (p-1)

  3. p,qp,q 互质,则 φ(p×q)=φ(p)×φ(q)\varphi(p\times q)=\varphi(p)\times\varphi(q),即 φ\varphi 是积性函数。

  4. 对于一个正整数 xx,将其质因数分解,ppxx 的质因子:x=p1c1×p2c2×p3c3××pkckx=p_1^{c_1}\times p_2^{c_2}\times p_3^{c_3}\times \dots \times p_k^{c_k}

φ(x)=x×p11p1×p21p2××pm1pm=x×px(11p)\varphi(x)=x \times \frac{p_1 - 1}{p_1} \times \frac{p_2 - 1}{p_2} \times \dots \times \frac{p_m-1}{p_m} = x \times \prod_{p \mid x}(1 - \frac{1}{p})

证明(推导):

φ(x)=φ(pxpc)=pxφ(pc)φ(x)=pxpc1×(p1)φ(x)=pxpc1×p×(p1)/p=pxpc×p1pφ(x)=x×pxp1p=x×px(11p)\varphi(x) = \varphi(\prod_{p \mid x}p^{c}) = \prod_{p \mid x}\varphi(p^{c}) \\ \varphi(x) = \prod_{p \mid x}p^{c-1}\times(p-1) \\ \varphi(x) = \prod_{p \mid x}p^{c-1}\times p \times (p-1) / p = \prod_{p \mid x}p^c\times\frac{p-1}{p} \\ \varphi(x) = x\times\prod_{p \mid x}\frac{p-1}{p}=x\times\prod_{p \mid x}(1-\frac{1}{p}) \\

证明(容斥原理):

先鸽了。

Tips 提示:由于浮点数有误差,使用公式计算欧拉函数时一般使用 x×质数 pxp1px \times \prod_{质数 \ p \mid x}\frac{p-1}{p}

  1. 对于一个质数 pp,如果有 pxp \mid x,那么 φ(x×p)=φ(x)×p\varphi(x \times p)=\varphi(x) \times p

证明:由于 pxp \mid x,所以 xx 的质因子包括 pp,只是 pp 的指数不同,结合上面推导出的公式,这个 pp,将会乘到 xx 上,xx 将会变成 x×px \times p,即 φ(x×p)=φ(x)×p\varphi(x \times p)=\varphi(x) \times p

  1. 对于一个质数 pp,如果有 pxp \nmid x,那么 φ(x×p)=φ(x)×(p1)\varphi(x \times p)=\varphi(x) \times (p-1)

证明 1:由于 pxp \nmid x,所以 xx 的质因子里没有 ppxx 会变成 x×px \times pxx 的质因子会增加一个 pp,原式会再乘上一个 p1p\frac{p-1}{p},即 φ(x×p)=φ(x)×p×p1p=φ(x)×(p1)\varphi(x \times p)=\varphi(x) \times p \times \frac{p-1}{p}=\varphi(x) \times (p-1)

证明 2:φ(x×p)=φ(x)×φ(p)=φ(x)×(p1)\varphi(x \times p)=\varphi(x) \times \varphi(p)=\varphi(x) \times (p-1)。

  1. dxφ(d)=n\sum_{d \mid x}\varphi(d)=n

求欧拉函数

试除法

xx 的欧拉函数:将 xx 质因数分解,用 resres 记录 xx 的欧拉函数,根据公式 φ(x)=x×质数 pxp1p\varphi(x) = x \times \prod_{质数 \ p \mid x}\frac{p-1}{p},初始时 res=xres=x,之后每找到一个质因子 ppres=res/p×(p1)res = res / p \times (p-1)。时间复杂度 O(x)O(\sqrt x)

int getphi(int x) {
    int res = x;
    for (int i = 2; i * i <= x; i ++ ) {
        if (x % i == 0) {
            res = res / i * (i - 1);
            while (x % i == 0) x /= i;
        }
    }
    if (x > 1) res = res / x * (x - 1);
    return res;
}

埃氏筛

void euler(int n) {
    for (int i = 1; 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);
            }
        }
    }
}

线性筛

void euler(int x) {
    memset(notp, 0, sizeof notp);
    notp[1] = true;
    phi[1] = 1;
    for (int i = 2; i <= x; i ++ ) {
        if (!notp[i]) pri[ ++ pcnt] = i, phi[i] = i - 1;
        for (int j = 1; i * pri[j] <= x && j <= pcnt; j ++ ) {
            notp[i * pri[j]] = true;
            if (i % pri[j]) phi[i * pri[j]] = phi[i] * phi[pri[j]];
            else {
                phi[i * pri[j]] = phi[i] * pri[j];
                break;
            }
        }
    }
}

同余

取模运算

aZ,bNa \in \mathbb{Z}, b \in \mathbb{N^*},定义:

a mod b={aan×na0(amodb)a<0a \ \text{mod} \ b = \begin{cases} a-\frac{a}{n} \times n \hspace{2.5em} a \ge 0 \\ -(-a \bmod b) \hspace{1.1em} a < 0 \end{cases}

这与 C++ 中的取模运算符的行为一致。

定义

(ab)modn=0(a-b) \bmod n=0,则称 aabb 同余,记为 ab(modn)a \equiv b \pmod n 读作 aabb 在模 nn 的意义下同余。

性质

  1. 反身性,自反性,传递性

  2. 如果 ab(modm)a \equiv b \pmod{m}cd(modm)c \equiv d \pmod m,则有 a±cb±d(modm)a \pm c \equiv b \pm d \pmod m

  3. 如果 ab(modm)a \equiv b \pmod mcd(modm)c \equiv d \pmod m,则有 acbd(modm)ac \equiv bd \pmod m

  4. 如果 ab(modm)a \equiv b \pmod m,则有 axbx(modm)a^x \equiv b^x \pmod m

  5. 如果 acbc(modm)ac \equiv bc \pmod m,则有 ab(modmgcd(m,c))a\equiv b \pmod{\frac{m}{gcd(m, c)}}

费马小定理

pp 是一个质数,且正整数 aa 满足 apa \bot p,则 ap11(modp)a^{p-1}\equiv 1 \pmod{p}

其逆否命题是:若 ap,ap1≢1(modp)a \bot p, a^{p-1} \not \equiv 1 \pmod p,则 pp 不是质数。

证明:
假设 apa(modp)a^{p} \equiv a \pmod p 成立,则
(a+1)p=a+(p1)a+(p2)a+...+(pp1)a+1(a+1)^{p}=a+\binom{p}{1}a+\binom{p}{2}a+...+\binom{p}{p-1}a+1
由于 (pq)=p!q!(pq)!\binom{p}{q}=\frac{p!}{q!(p-q)!},当 q(0,p)q \in (0, p),有 (pq)a0(modp)\binom{p}{q}a \equiv 0 \pmod p
(a+1)pa+1(modp)(a+1)^{p}\equiv a+1 \pmod p
显然有 1p1(modp)1^{p} \equiv 1 \pmod p,则 apa(modp)a^{p} \equiv a \pmod p 得证。
由于 apa \bot p,所以 ap11(modp)a^{p-1}\equiv 1 \pmod p

欧拉定理

若正整数 a,pa, p 满足 apa \bot p,则 aφ(p)1(modp)a^{\varphi(p)} \equiv 1 \pmod p

逆元

线性预处理逆元

1n1 \sim n 的逆元

给定一个数列 a1,a2...ana_1, a_2 ... a_n

Exgcd

Miller-Rabin 素性检验

二次探测定理:

上述的算法效率太低,我们考察一个更高效的算法。

首先用到费马小定理:

pp 为质数,apa \bot p,则 ap11(modp)a^{p-1} \equiv 1 \pmod p

其逆命题是:

ap,ap11(modp)a \bot p, a^{p-1} \equiv 1 \pmod p,则 pp 是质数。

然而这个逆命题是不成立的,对于一些合数,仍满足 ax1modp=1a^{x-1} \bmod p = 1,这样的数叫费马伪素数。

可以考虑多随机几组 aa,这样能排除大量的上述情况。

但是这并不等价于对于若干个 aa, 若 ap11(modp)a^{p-1} \equiv 1\pmod p,则 pp 是质数。

有些数满足  ap,ap1(modp),a2\forall \ a \perp p, a^p \equiv 1\pmod p, a \ge 2,被称为卡迈克尔数。

费马小定理来判断质数是错误的。我们考虑引入新的定理来提高检测的正确性。

二次探测定理:

pp 为质数, 则当 x<px < p 时,x21(modp)x^2 \equiv 1\pmod p 有且仅有解 11p1p-1

我们同样写出逆否命题:

x<px < p 时,若 x21(modp)x^2 \equiv 1\pmod p 的解不只有 11p1p-1,则 pp 不为质数。

接下来就是 Miller Rabin 素性检验算法的流程:

对于要检验的数 nn,我们设费马小定理中的指数 p1=d×2rp-1=d \times 2^{r},若 r1r \ge 1,根据二次探测定理,若 (ap12)21(modp)(a^{\frac{p-1}{2}})^2 \equiv 1 \pmod p 的解不只有 p1p-111 的话,则 pp 不为质数,即判断 ap12a^{\frac{p-1}{2}} 是不是等于 p1p-111,以此类推,重复 rr 轮即可。

注意到 pp 无法通过以 pp 为底的素性检验,所以你需要特判为质数的底数。

若单次乘法的复杂度为 O(1)O(1),这样做的时间复杂度为 O(klog2n)O(k \log^2 n)

可以发现其实仍有优化空间,复杂度瓶颈在二次探测。我们考虑把二次探测的过程翻过来,把 d×2rdd \times 2^r \rightarrow d 变为 dd×2rd \rightarrow d \times 2^r,我们只需要算出 ada^d,然后平方 rr 次即可。复杂度 O(klogn)O(k \log n)

当然我们还可以光速幂,不过这样只是常数上的优化了。

Miller Rabin 检验依旧有错误的概率。我们可以通过选取适合的底数,来避免这一情况的发生。

  • 如果 n<2,047n < 2,047,只需测试 a=2a = 2
  • 如果 n<1,373,653n < 1,373,653,只需测试 a=2a = 233
  • 如果 n<9,080,191n < 9,080,191,只需测试 a=31a = 317373
  • 如果 n<25,326,001n < 25,326,001,只需测试 a=2,3a = 2, 355
  • 如果 n<3,215,031,751n < 3,215,031,751,只需测试 a=2,3,5a = 2, 3, 577
  • 如果 n<4,759,123,141n < 4,759,123,141,只需测试 a=2,7a = 2, 76161
  • 如果 n<1,122,004,669,633n < 1,122,004,669,633,只需测试 a=2,13,23a = 2, 13, 2316628031662803
  • 如果 n<2,152,302,898,747n < 2,152,302,898,747,只需测试 a=2,3,5,7a = 2, 3, 5, 71111
  • 如果 n<3,474,749,660,383n < 3,474,749,660,383,只需测试 a=2,3,5,7,11a = 2, 3, 5, 7, 111313
  • 如果 n<341,550,071,728,321n < 341,550,071,728,321,只需测试 a=2,3,5,7,11,13a = 2, 3, 5, 7, 11, 131717
  • 如果 n<3,825,123,056,546,413,051n < 3,825,123,056,546,413,051,只需测试 a=2,3,5,7,11,13,17,19a = 2, 3, 5, 7, 11, 13, 17, 192323
  • 如果 n<18,446,744,073,709,551,616=264n < 18,446,744,073,709,551,616 = 2^{64},只需测试 a=2,3,5,7,11,13,17,19,23,29,31a = 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 313737
  • 如果 n<318,665,857,834,031,151,167,461n < 318,665,857,834,031,151,167,461,只需测试 a=2,3,5,7,11,13,17,19,23,29,31a = 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 313737
  • 如果 n<3,317,044,064,679,887,385,961,981n < 3,317,044,064,679,887,385,961,981,只需测试 a=2,3,5,7,11,13,17,19,23,29,31,37a = 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 374141

这样选择底数可以保证 100%100 \% 正确。

代码实现

const int pa[] = {2, 3, 5, 7, 11, 13, 17};

int qmul(int a, int b, int mod) {
	a %= mod, b %= mod;
	int c = (long double)a * b / mod;
	int d = a * b - mod * c;
	if (d < 0) return d + mod;
	if (d >= mod) return d - mod;
	return d;
}

int qpow(int a, int b, int mod) {
	int res = 1;
	for (; b; b >>= 1) {
		if (b & 1) res = qmul(res, a, mod);
		a = qmul(a, a, mod);
	}
	return res;
}

bool mrtest(int n, int a) {
	int d = n - 1, r = 0;
	while (d % 2 == 0) d >>= 1, ++ r;
	int x = qpow(a, d, n);
	if (x == 1) return true;
	for (int i = 0; i < r; i ++ ) {
		if (x == n - 1) return true;
		x = qmul(x, x, n);
	}
	return false;
}

bool isprime(int n) {
	if (n < 2) return false;
	for (int i = 0; i < 7; i ++ ) {
		if (n == pa[i]) return true;
		if (!mrtest(n, pa[i])) return false;
	}
	return true;
}
基础数论学习笔记
本文作者
Sky390
发布于
2022-08-20
版权协议
转载或引用本文时请遵守许可协议,注明出处、不得用于商业用途!