数论学习笔记

主要参考 OI-Note Chapter4.1 整除与同余 - 知乎

整除

\(a / b (b \ne 0)\) 为整数,则称 \(b\) 整除 \(a\) ,记作 \(b \mid a\) 。若 \(a / b\)\(c / b\) 的余数相等,则称 \(a, c\)\(b\) 同余。

同余

关于同余,有以下命题等价:

  1. \(a\)\(b\) 是模 \(d\) 同余的。
  2. 存在某个整数 \(n\) ,使 \(a = b + nd\)
  3. \(d\) 整除 \(a - b\)

由此可以轻易推出以下性质:

同余的基本性质

  • \[a \equiv b \pmod p \text{且} c \equiv d \pmod p \Rightarrow a \pm c \equiv b \pm d \]

  • \[a \equiv b \pmod p \Rightarrow ak \equiv bk \pmod {pk} \]

  • \[k\mid p \text{且} a \equiv b \pmod p \Rightarrow a \equiv b \pmod k \]

模运算基本性质

  • \[(a + b) \bmod p = ((a \bmod p) + (b \bmod p)) \bmod p \]

  • \[ab \bmod p = (a \bmod p)(b \bmod p) \bmod p \]

  • \[a \bmod kb \bmod b = a \bmod b \]

欧几里得辗转相除法(gcd)

给定整数 \(a, b\) ,将它们的最大公因数记作 \(\gcd(a, b)\) ,欧几里得辗转相除法便是用来求 \(\gcd(a, b)\) 的,因而简称 \(\gcd\)
\(a, b\) 的公因数集合为 \(T\)\(b , a \bmod b\) 的公因数集合为 \(T'\) ,有 \(T = T'\) 。证明:
\(u \subseteq T\)\(a = xu, b = yu\) ,$$a \bmod b = a - b \left \lfloor a / b \right \rfloor = xu - yu(\left \lfloor a / b \right \rfloor) = u[x - y(\left \lfloor a / b \right \rfloor)]$$ ,所以 \(u \mid a \bmod b\)\(T \subseteq T'\)
同样的,记 \(v \subseteq T'\)\(b = nv, a \bmod b = mv\) ,$$a = a \bmod b + b \left \lfloor a / b \right \rfloor = mv + nv(\left \lfloor a / b \right \rfloor) = v[m + n\left \lfloor a / b \right \rfloor]$$ ,所以 \(v \mid a\)\(T' \subseteq T\)

综上, \(\gcd(a, b) = \gcd(b, a \bmod b)\) ,因而可以直接递归求解。时间复杂度为 \(\log(n)\)

边界:当 \(b = 0\) 时,\(\gcd(a, b) = a\)

code:

int gcd(int a, int b){
    return b ? gcd(b, a % b) : a;
}

扩展欧几里得(exgcd)

由欧几里得辗转相除法,我们可以运用这个算法在求最大公因数的同时求出满足 $$ax + by = \gcd(a, b)$$ 的正整数解 \(x, y\)

对于边界条件 \(b = 0\)\(x = 1, y = 0\) 就是一组合法解(当然,此处 \(y\) 可以取任意数)。那么,设 \(a' = b, b' = a \bmod b\) ,且我们已经求出 \(x_0, y_0\) 满足 \(a'x_0 + b'y_0 = \gcd(a', b')\) ,于是:

\[\begin{aligned} \gcd(a, b) &= \gcd(a', b') \\ &= a'x_0 + b'y_0 \\ &= bx_0 + (a\bmod b)y_0 \\ &= bx_0 + (a - b \left \lfloor a / b \right \rfloor)y_0 \\ &= ay_0 + b(x_0 - \left \lfloor a / b \right \rfloor y_0) \end{aligned} \]

因此,满足 \(ax + by = \gcd(a, b)\)\(x = y_0, y = x_0 - \left \lfloor a / b \right \rfloor y_0\)

code:

int exgcd(int a, int b, int &x, int &y){
    if(!b){
        x = 1, y = 0;
        return a;
    }
    int a1 = exgcd(b, a % b, x, y);
    int x1 = y, y1 = x - a / b * y;
    x = x1, y = y1;
    return a1;
}

乘法逆元

对于一个数 \(a\) ,若 \(ab = 1\) ,那么我们称 \(a\) 的逆元为 \(b\) ,记作 \(a^{-1}\) 。在同余中,则是若 \(ab \equiv 1\) , 则 \(b\)\(a\) 的逆元。通常,我们通过找到 \(a\) 的逆元来避免除法。给定 \(a\)\(b\) ,我们需要求出 \(x\) 满足 \(ax \equiv 1 \pmod b\)

逆元唯一性定理:逆元若存在,则总是唯一的。
反证法。设有 \(x \not \equiv y\) 使得 \(ax \equiv ay \equiv 1\) ,则有 \(axy \equiv ax(y) \equiv y\) ,且 \(axy \equiv ay(x) \equiv x\) , 则 \(x \equiv y\) ,矛盾。
逆元存在性定理:在模 \(m\) 下,当且仅当 \(a \bot m\) 时,\(a\) 的逆元存在。后续补充证明。

事实上, \(ax \equiv 1 \pmod b\) 等价于 \(ax + by = \gcd(a, b)\) 。由逆元存在性定理,\(a \bot b\) 时, \(ax + by = 1\) 。所以 \(ax = 1 - by\)\(ax \equiv 1\) 。而若 \(ax \equiv 1 \pmod b\) ,则 \(ax - 1 \equiv 0 \pmod b\) ,所以令 \(y = \frac{ax - 1}{b}\) , 就有 \(ax + by = 1\) 。因此这两者等价。我们就可以直接使用exgcd求出 \(a\) 在模 \(b\) 下的乘法逆元。不过有一个需要注意的是,使用exgcd求出来的逆元可能是负数,输出时加一个 (x % p + p) % p 就好啦。

线性求逆元

我们知道 \(a \times a^{-1} \equiv 1\)

\(p = n \times i + r\) ,就有:

\[n \times i + r \equiv 0 \pmod p \]

同时乘以 \(i^{-1}, r^{-1}\) 得:

\[n \times r^{-1} + i^{-1} \equiv 0 \]

移项得:

\[i^{-1} \equiv -n \times r^{-1} \]

\[i^{-1} \equiv -\left \lfloor p / i \right \rfloor (p \bmod i)^{-1} \]

又因为 \(p \bmod i\)\(i\) 小,我们就可以 \(O(n)\) 求逆元了!

裴蜀定理

不定方程 \(ax + by = c\) 有整数解 \(x, y\) 的充要条件是 \(\gcd(a, b) \mid c\)
证明:
\(\gcd(a, b) \mid c\) 时,我们可以先用exgcd求出\(ax +by = \gcd(a, b)\) 的解,然后同时乘以 \(\ c / gcd(a, b)\) 即可得出解。
\(\gcd(a, b) \not \mid c\) 时,在该方程两边同时除以 \(\gcd(a, b)\) ,发现方程左边为整数,右边为分数,则必定无解。

由此,我们就可以运用裴蜀定理直接证明逆元存在性定理了。

另外, 若 \(c \bot m, ac \equiv bc \pmod m\) ,运用逆元可以得出 \(a \equiv b\) 。这也是一条同余的性质。

P5656 【模板】二元一次不定方程 (exgcd)

虽然是个板子题,但是非常恶心。

无解情况裴蜀定理判定即可。
对于有解:
首先我们就可以通过exgcd求出满足 \(ax + by = c\) 的一组整数解 \(x_0, y_0\) ,记 \(d = \gcd(a, b)\) 。怎么由一组特解推出通解呢?

由观察可知,当 \(x\) 变大时, \(y\) 会变小。因此设 \(x_0 + kp, y_0 - kq\) 为另外一组解 ( \(p, q\) 为一个定值),我们通过改变 \(k\) 来求得每一组解。这个时候可能聪明的你会感觉到有些不对劲:为什么 \(p\)\(q\) 的系数绝对值刚好都是 \(k\) 呢?就不能 \(x + (k + 1)p, y_0 - kq\) 吗? \(p, q\) 又可以是什么定值呢?我们来证明一下:
不管\(k\),我们可以列出方程组:

\[\begin{cases} ax_0 + by_0 = c \\ a(x_0 + p) + b(y_0 - q) = c \end{cases} \]

可以解得 \(ap = bq, p = \frac{bq}{a}, q = \frac{ap}{b}\) 。也就是 \(p, q\) 需要满足这个等式才能构造出另外一组解。但还不够,我们需要 \(p, q\) 为最小的正整数 \(p, q\) ,以此来通过调整系数 \(k\) 求出每一组解,要求 \(a \mid bq\)\(b \mid ap\) 。所以 \(bp_{\min} = \operatorname{lcm}(a, b) = \frac{ab}{d}\) (此处详见下面的最大公倍数),\(p_{\min} = \frac{a}{d}\) 。同理 \(q_{\min} = \frac{b}{d}\) 。我们就求出了 \(p, q\) 的最小正整数。

我们设另一组解为 \(x_0 + np, y_0 - mq\) ,则:

\[\begin{cases} ax_0 + by_0 = c \\ a(x_0 + np) + b(y_0 - mq) = c \end{cases} \]

解得 \(anp = bmq\) 。又由上面的 \(ap = bq\) ,我们就会发现 \(n = m\) ,所以 \(k = n = m\) 就好啦!

之后具体细节分类讨论即可(然后就调了一上午) 。推荐题解第一篇,感觉最简单易懂!(加 longlong, 不然就会在不知不觉中浪费1个小时QAQ)

#include<bits/stdc++.h>
using namespace std;

#define int long long
#define mo 19260817

int a, b, c;

int exgcd(int a, int b, int &x, int &y){
  if(!b){
    x = 1, y = 0;
    return a;
  }
  int a1 = exgcd(b, a % b, x, y);
  int x1 = y, y1 = x - a / b * y;
  x = x1, y = y1;
  return a1;
}

signed main(){
//   freopen("shuju.in", "r", stdin);
  ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  int TN;
  cin >> TN;
  while(TN--){
    cin >> a >> b >> c;
    int x, y;
    int gcd = exgcd(a, b, x, y);
    x *= c / gcd, y *= c / gcd;
    int p = b / gcd, q = a / gcd;
    if(c % gcd) {
      cout << -1 << endl;
      continue;
    }
    int sl = ceil((1.0 - x) / p), sr = floor((y - 1.0) / q);
    if(sl > sr) {
      cout << x + sl * p << " " << y - sr * q; 
    }
    else{
      cout << sr - sl + 1 << " ";
      cout << x + sl * p << " " << y - sr * q << " " << x + sr * p << " " << y - sl * q;
    }
    cout << endl;
  }
  return 0;
}

欧拉定理

\(a \bot m\) 时, $$a ^ {\varphi(m)} \equiv 1 \pmod m$$
[[欧拉函数&欧拉定理]]

详细证明可见 欧拉函数 & 欧拉定理
证明:
我们构造一个数 \(k\) ,只需使得 \(ka ^ {\varphi(m)} \equiv k\) ,且 \(k \bot m\) 即可证明欧拉定理。设在模 \(m\) 下的剩余系中与 \(m\) 互质的数的集合为 \(\left\{ b_1, b_2, ... b_n \right\} (n = \varphi(m))\) ,令 \(k = b_1b_2...b_n\) ,这时 \(k \bot m\) 。又因为 \(a \bot m\) , 所以集合 \(\left\{ ab_1, ab_2, ..., ab_n\right\}\) 中每个数都与 \(m\) 互质,即 \(\left\{ b_1, b_2, ... b_n \right\} = \left\{ ab_1, ab_2, ..., ab_n\right\}\) 。那 \(ab_1 * ab_2* ...*ab_n = a ^ {\varphi(m)}k \equiv k\) 。证毕。

由欧拉定理,我们能直接得出费马小定理,实际上欧拉定理就是费马小定理的推广。

最小公倍数

我们已经知道可以通过 \(\gcd\) 求出 \(a, b\) 的最大公因数,那么有没有类似的快捷方法求出 \(a, b\) 的最大公倍数呢?

当然有!通过算术基本定理,我们将 \(a, b\) 表示成如下形式:

\[a = p_1^{n_1}p_2^{n_2}...p_x^{n_x} \]

\[b = p_1^{m_1}p_2^{m_2}...p_x^{m_x} \]

其中 \(p\) 属于 \(a, b\) 的所有质因数集合。

那么

\[\gcd(a, b) = p_1^{\min(n_1,m_1)}p_2^{\min(n_2,m_2)}...p_x^{\min(n_x, m_x)} \]

\[\operatorname{lcm}(a, b) = p_1^{\max(n_1,m_1)}p_2^{\max(n_2,m_2)}...p_x^{\max(n_x, m_x)} \]

于是

\[\operatorname{lcm} = \frac{ab}{\gcd(a,b)} \]

Lucas定理

前置知识:二项式定理
可以看看容斥定理及二项式反演

Lucas定理:

\[\binom nm \equiv \binom{\left \lfloor \frac{n}{p} \right \rfloor}{\left \lfloor \frac{m}{p} \right \rfloor} \times \binom{n\bmod p}{m\bmod p} \pmod p \]

其中 \(p\) 是质数。
可以看成是 \(n, m\)\(p\) 进制下各数码的组合乘积。

证明(不要被式子吓到啦,很简单的):

\(\binom nm\) 可以看成 \((1+x)^n\)\(x^m\) 项的系数,我们就尝试写一下:

\[(1+x)^n=(1+x)^{p\lfloor\frac{n}{p}\rfloor}(1+x)^{n\bmod p} \]

因为 \(p\) 是质数,所以对于 \(\forall i \in [1,p-1]\)\(i\) 在模 \(p\) 下均有逆元,\(\binom pi = \frac{p}{i}\binom{p-1}{i-1} \equiv 0 \pmod p\)

\[(1+x)^p=\sum_{i=0}^p\binom pix^i \equiv 1+x^p \]

因为中间的系数在模 \(p\) 下为 \(0\) ,在 \((1+x)^n\) 中相加不会对模 \(p\)\(x^m\) 项的系数有所影响,就可以直接忽略。于是我们继续:

\[\begin{aligned} (1+x)^{p\lfloor\frac{n}{p}\rfloor}(1+x)^{n\bmod p} &\equiv (1+x^p)^{\lfloor\frac{n}{p}\rfloor}(1+x)^{n\bmod p}\\ &=\sum_{i=0}^{\lfloor\frac{n}{p}\rfloor}\binom {\lfloor\frac{n}{p}\rfloor}{i}x^{pi}\sum_{i=0}^{n\bmod p}\binom{n\bmod p}{i}x^i \end{aligned} \]

发现这个式子要想凑出 \(x^m\) 那一项,因为左边只能提供 \(p\) 的倍数次项,右边只能提供模 \(p\) 的余数的项,所以对 \(x^m\) 的系数有贡献的项必须是是左边提供 \(\lfloor\frac{m}{p}\rfloor\) 的项, 右边提供 \(m \mod p\) 的项,所以 \(x^m\) 项的系数在模 \(p\) 下就是

\[\binom{\lfloor\frac{n}{p}\rfloor}{\lfloor \frac{m}{p}\rfloor}\binom{n\bmod p}{m\bmod p} \]

证完!

素数的线性筛法

为了让一个合数只被标记一次,我们设法让一个合数只会被它的最小素因子标记一次。

vector<int> p;
int tag[N];
void init(int n){
	tag[1] = 1;
	for(int i = 2; i <= n; i ++){
		if(!tag[i]) p.push_back(i);
		for(auto j : p){
			if(j * i > n) break;
			tag[i * j] = 1;
			if(i % j == 0) break;
			//这里我们假设i = k*j, 下一个素数为g, g > j
			//i*g = k*j*g, 因为k*g > i,所以i*g在之后循环到k*g时被标记,这里就不用标记了
		}
	}
}

整除分块

能够在 \(O(\sqrt n)\) 的时间内求出 \(\sum_{i=1}^n \frac{n}{i}\)

正常肯定是 \(O(n)\) 的,但是考虑一下如何加快。随便画一个反比例函数图像,会发现有对于每个 \(i\) ,几乎都会有一段连续区间 \(\frac{n}{i}\) 的值是相同的。结论是,对于 \(i\) 所在的块,块的右端点是 \(\frac{n}{\lfloor\frac{n}{i}\rfloor}\)

另外一个结论,$$\sum_{i=1}^n[x\mid i] = \lfloor\frac{n}{x}\rfloor$$

int g(int n){
  int ans = 0;
  for(int l = 1, r; l <= n; l = r + 1){
    r = n / (n / l);
    ans += (r - l + 1) * n / l;
  }
  return ans;
}

威尔逊定理

\(p\) 为素数等价于

\[(p-1)!\equiv-1\pmod p \]

posted @ 2023-10-30 23:07  星影流灿  阅读(58)  评论(0)    收藏  举报