Day 25 - 同余与乘法逆元
欧拉函数
定义
欧拉函数(\(\text{Euler's totient function}\)),即 \(\varphi(n)\),表示的是小于等于 \(n\) 和 \(n\) 互质的数的个数。
比如说 \(\varphi(1) = 1\)。
当 \(n\) 是质数的时候,显然有 \(\varphi(n) = n - 1\)。
性质
-
欧拉函数是积性函数。
即对任意满足 \(\gcd(a, b) = 1\) 的整数 \(a,b\),有 \(\varphi(ab) = \varphi(a)\varphi(b)\)。
特别地,当 \(n\) 是奇数时 \(\varphi(2n) = \varphi(n)\)。
证明参见剩余系的复合。
-
\(n = \sum_{d \mid n}{\varphi(d)}\)。
证明:
利用莫比乌斯反演相关知识可以得出。
也可以这样考虑:如果 \(\gcd(k, n) = d\),那么 \(\gcd(\dfrac{k}{d},\dfrac{n}{d}) = 1, ( k < n )\)。
如果我们设 \(f(x)\) 表示 \(\gcd(k, n) = x\) 的数的个数,那么 \(n = \sum_{i = 1}^n{f(i)}\)。
根据上面的证明,我们发现,\(f(x) = \varphi(\dfrac{n}{x})\),从而 \(n = \sum_{d \mid n}\varphi(\dfrac{n}{d})\)。注意到约数 \(d\) 和 \(\dfrac{n}{d}\) 具有对称性,所以上式化为 \(n = \sum_{d \mid n}\varphi(d)\)。
-
若 \(n = p^k\),其中 \(p\) 是质数,那么 \(\varphi(n) = p^k - p^{k - 1}\)。
(根据定义可知) -
由唯一分解定理,设 \(n = \prod_{i=1}^{s}p_i^{k_i}\),其中 \(p_i\) 是质数,有 \(\varphi(n) = n \times \prod_{i = 1}^s{\dfrac{p_i - 1}{p_i}}\)。
证明:
-
引理:设 \(p\) 为任意质数,那么 \(\varphi(p^k)=p^{k-1}\times(p-1)\)。
证明:显然对于从 1 到 \(p^k\) 的所有数中,除了 \(p^{k-1}\) 个 \(p\) 的倍数以外其它数都与 \(p^k\) 互素,故 \(\varphi(p^k)=p^k-p^{k-1}=p^{k-1}\times(p-1)\),证毕。
接下来我们证明 \(\varphi(n) = n \times \prod_{i = 1}^s{\dfrac{p_i - 1}{p_i}}\)。由唯一分解定理与 \(\varphi(x)\) 函数的积性
\[\begin{aligned} \varphi(n) &= \prod_{i=1}^{s} \varphi(p_i^{k_i}) \\ &= \prod_{i=1}^{s} (p_i-1)\times {p_i}^{k_i-1}\\ &=\prod_{i=1}^{s} {p_i}^{k_i} \times(1 - \frac{1}{p_i})\\ &=n~ \prod_{i=1}^{s} (1- \frac{1}{p_i}) &\square \end{aligned} \]
-
-
对任意不全为 \(0\) 的整数 \(m,n\),\(\varphi(mn)\varphi(\gcd(m,n))=\varphi(m)\varphi(n)\gcd(m,n)\)。
可由上一条直接计算得出。
实现
如果只要求一个数的欧拉函数值,那么直接根据定义质因数分解的同时求就好了。这个过程可以用 \(\text{Pollard Rho}\) 算法优化。
#include <cmath>
int euler_phi(int n) {
int m = int(sqrt(n + 0.5));
int ans = n;
for (int i = 2; i <= m; i++)
if (n % i == 0) {
ans = ans / i * (i - 1);
while (n % i == 0) n /= i;
}
if (n > 1) ans = ans / n * (n - 1);
return ans;
}
注:如果将上面的程序改成如下形式,会提升一点效率:
#include <cmath>
int euler_phi(int n) {
int ans = n;
for (int i = 2; i * i <= n; i++)
if (n % i == 0) {
ans = ans / i * (i - 1);
while (n % i == 0) n /= i;
}
if (n > 1) ans = ans / n * (n - 1);
return ans;
}
欧拉定理
与欧拉函数紧密相关的一个定理就是欧拉定理。其描述如下:
若 \(\gcd(a, m) = 1\),则 \(a^{\varphi(m)} \equiv 1 \pmod{m}\)。
扩展欧拉定理
当然也有扩展欧拉定理
裴蜀定理
定义
裴蜀定理,又称贝祖定理、贝祖等式。是一个关于最大公约数的定理。
其内容是:
设 \(a,b\) 是不全为零的整数,对任意整数 \(x,y\),满足 \(\gcd(a,b)\mid ax+by\),且存在整数 \(x,y\), 使得 \(ax+by=\gcd(a,b)\).
证明
对于第一点
由于 \(\gcd(a,b)\mid a,\gcd(a,b)\mid b\)
所以 \(\gcd(a,b)\mid ax,\gcd(a,b)\mid by\),其中 \(x,y\) 均为整数
因此 \(\gcd(a,b)\mid ax+by\)
对于第二点
-
若任何一个等于 \(0\), 则 \(\gcd(a,b)=a\). 这时定理显然成立。
-
若 \(a,b\) 不等于 \(0\).
由于 \(\gcd(a,b)=\gcd(a,-b)\),
不妨设 \(a,b\) 都大于 \(0\),\(a\geq b,\gcd(a,b)=d\).
对 \(ax+by=d\), 两边同时除以 \(d\), 可得 \(a_1x+b_1y=1\), 其中 \((a_1,b_1)=1\).
转证 \(a_1x+b_1y=1\).
我们先回顾一下辗转相除法是怎么做的,由 \(\gcd(a, b) \rightarrow \gcd(b,a\mod b) \rightarrow \dots\) 我们把模出来的数据叫做 \(r\) 于是,有
\[\gcd(a_1,b_1)=\gcd(b_1,r_1)=\gcd(r_1,r_2)=\cdots=(r_{n-1},r_n)=1 \]把辗转相除法中的运算展开,做成带余数的除法,得
\[\begin{aligned}a_1 &= q_1b_1+r_1 &(0\leq r_1<b_1) \\ b_1 &= q_2r_1+r_2 &(0\leq r_2<r_1) \\ r_1 &= q_3r_2+r_3 &(0\leq r_3<r_2) \\ &\cdots \\ r_{n-3} &= q_{n-1}r_{n-2}+r_{n-1} \\ r_{n-2} &= q_nr_{n-1}+r_n \\ r_{n-1} &= q_{n+1}r_n\end{aligned} \]不妨令辗转相除法在除到互质的时候退出则 \(r_n=1\) 所以有(\(q\) 被换成了 \(x\),为了符合最终形式)
\[r_{n-2}=x_nr_{n-1}+1 \]即
\[1=r_{n-2}-x_nr_{n-1} \]由倒数第三个式子 \(r_{n-1}=r_{n-3}-x_{n-1}r_{n-2}\) 代入上式,得
\[1=(1+x_nx_{n-1})r_{n-2}-x_nr_{n-3} \]然后用同样的办法用它上面的等式逐个地消去 \(r_{n-2},\cdots,r_1\),
可证得 \(1=a_1x+b_1y\).
这样等于是一般式中 \(d=1\) 的情况。
推广
逆定理
设 \(a, b\) 是不全为零的整数,若 \(d > 0\) 是 \(a, b\) 的公因数,且存在整数 \(x, y\), 使得 \(ax+by=d\),则 \(d = \gcd(a, b)\)。
特殊地,设 \(a, b\) 是不全为零的整数,若存在整数 \(x, y\), 使得 \(ax+by=1\),则 \(a, b\) 互质。
多个整数
裴蜀定理可以推广到 \(n\) 个整数的情形:设 \(a_1, a_2, \dots, a_n\) 是不全为零的整数,则存在整数 \(x_1, x_2, \dots, x_n\), 使得 \(a_1 x_1 + a_2 x_2 + \cdots + a_n x_n=\gcd(a_1, a_2, \dots, a_n)\)。其逆定理也成立:设 \(a_1, a_2, \dots, a_n\) 是不全为零的整数,\(d > 0\) 是 \(a_1, a_2, \dots, a_n\) 的公因数,若存在整数 \(x_1, x_2, \dots, x_n\), 使得 \(a_1 x_1 + a_2 x_2 + \cdots + a_n x_n=d\),则 \(d = \gcd(a_1, a_2, \dots, a_n)\)。
应用
给出 \(n\) 张卡片,分别有 \(l_i\) 和 \(c_i\)。在一条无限长的纸带上,你可以选择花 \(c_i\) 的钱来购买卡片 \(i\),从此以后可以向左或向右跳 \(l_i\) 个单位。问你至少花多少元钱才能够跳到纸带上全部位置。若不行,输出 \(-1\)。
分析该问题,发现想要跳到每一个格子上,必须使得所选数 \(l_{i_1}, \dots, l_{i_k}\) 通过数次相加或相减得出的绝对值为 \(1\),也即存在整数 \(x_1, \dots, x_n\) 使得 \(l_{i_1} x_1 + \cdots + l_{i_k} x_k = 1\)。由多个整数的裴蜀定理逆定理,这相当于从数组 \(l_1, \dots, l_n\) 选择若干个数,满足它们的最大公因数为 1,同时要求代价和最小。
解法 1:我们可以转移思想,因为这些数互质,即为 \(0\) 号节点开始,每走一步求 \(\gcd\)(节点号,下一个节点),同时记录代价(求边权),就成为了从 \(0\) 通过不断 \(\gcd\) 最后变为 \(1\) 的最小代价。
由于:互质即为最大公因数为 \(1\),\(\gcd(0,x)=x\) 这两个定理,可以证明该算法的正确。选择优先队列优化 Dijkstra 求解。
不过还有个问题,即为需要记录是否已经买过一个卡片,开数组标记由于数据范围达到 \(10^9\) 会超出内存限制,可以想到使用 unordered_map
(比普通的 map
更快地访问各个元素,迭代效率较低)
解法 2:从数组 \(l_1, \dots, l_n\) 选择若干个数,满足它们的最大公因数为 1,且代价和最小,由此可以想到 0-1 背包问题。
设 \(f_{i, j}\) 表示考虑前 \(i\) 个数且最大公因数为 \(j\) 的最小代价,则有转移方程:
DP 后最终的总代价即为 \(f_{n, 1}\)。
如同一般的 0-1 背包问题,可以用滚动数组优化,去掉第一维。而这里 300 个数可达的最大公因数 \(j\) 是很稀疏的,因此还可以使用 unordered_map
代替数组储存下标 \(j\),优化内存并进一步减少枚举量。
实际上,这里解法 1 建出的图便是解法 2 中动态规划的状态转移图,解法 2 相当于用动态规划求有向无环图的最短路,因此解法 1 和解法 2 是等价的。但解法 2 无需储存全图,同时 DP 的时间复杂度为 \(O(n + m)\),相比 Dijkstra 算法更低,因此解法 2 在时间和空间上更优。
进一步结论
对自然数 \(a\)、\(b\) 和整数 \(n\),\(a\) 与 \(b\) 互素,考察不定方程:
其中 x 和 y 为自然数。如果方程有解,称 n 可以被 a、b 表示。
记 \(C=ab-a-b\)。由 a 与 b 互素,C 必然为奇数。则有结论:
对任意的整数 n,n 与 \(C-n\) 中有且仅有一个可以被表示。
即:可表示的数与不可表示的数在区间 \([0,C]\) 对称(关于 C 的一半对称)。0 可被表示,C 不可被表示;负数不可被表示,大于 C 的数可被表示。
证明
由于 a、b 互素,因此原方程有整数解。设解为:
其中 t 为整数。取适当的 t,使得 y 位于 0 到 \(a-1\) 之间。这只需在 \(y_0\) 上加上或减去若干个 a,即可得到这样的 t。
第一步:证明大于 C 的数都可以被表示。当 n 大于 C 时:
于是 x 也是非负整数。
第二步:证明 C 不可被表示,进而 n 与 \(C-n\) 不可能都被表示。
反证法。若 \(ax+by=ab-a-b\) 有非负整数解 x、y,则:
由于 a 与 b 互素,所以 a 整除 \(y+1\),b 整除 \(x+1\),a 不超过 \(y+1\),b 不超过 \(x+1\)。于是有:
矛盾!第二步证完。
第三步:证明如果 n 不可被表示,则 \(C-n\) 可被表示。
由上可知,若 n 不可被表示,由于上述方程中已规定 y 在 0 到 \(a-1\) 之间,则 x 为负。所以:
显然 \(-x-1\) 和 \(a-1-y\) 均非负,于是 \(C-n\) 可被表示。
几何意义
重新观察方程 \(ax+by=n\),将它看成一条直线。直线与两坐标轴在第一象限围成三角形。
当 \(n<ab\) 的时候,这个直线在第一象限,至多只能通过一个整点。
根据上述讨论:当 n 可以被表示的时候,直线恰好经过一个整点;当 n 不可以被表示的时候,直线不经过整点(在第一象限)。
这结论也可以理解为:作三角形 \((0,0)(b,0)(0,a)\)。随着 n 从 0 不断增加,直线向右上方平移,整点会一个一个地通过直线,直到最后才撞上两个整点。
因此,小于等于 n 的能被表示的非负整数的数量,恰好就是直线 \(ax+by=n\)(含)与两坐标轴(含)在第一象限围成三角形覆盖的整点个数。
另一种解释
考虑模 b 意义下每个剩余系中最小能被表示的值是多少——大于他们的可以通过增加若干个 b 得到。
观察原方程,a 的若干倍数 \(0, a,\cdots, (b−1)a\) 在 \(\pmod b\) 意义下互不相同。这些数恰好是这些最小值。那么当 \(n<ab\) 时,小于等于 n 的能被表示的非负整数的数量是:
这是一个非常经典的直线下整点问题,恰好是这条直线:
即 \(ax+by=n\)。
使用类欧几里得算法可以在 \(O(\log \max(a,b))\) 的时间内求解。因此我们得到了计算小于等于 n 的能被表示的非负整数的数量的工具。
题目
P3951 NOIP2017 提高组 小凯的疑惑/蓝桥杯 2013 省 买不到的数目
费马小定理 & 欧拉定理
费马小定理
定义
若 \(p\) 为素数,\(\gcd(a, p) = 1\),则 \(a^{p - 1} \equiv 1 \pmod{p}\)。
另一个形式:对于任意整数 \(a\),有 \(a^p \equiv a \pmod{p}\)。
证明
设一个质数为 \(p\),我们取一个不为 \(p\) 倍数的数 \(a\)。
构造一个序列:\(A=\{1,2,3\dots,p-1\}\),这个序列有着这样一个性质:
证明:
又因为每一个 \(A_i\times a \pmod p\) 都是独一无二的,且 \(A_i\times a \pmod p < p\)
得证(每一个 \(A_i\times a\) 都对应了一个 \(A_i\))
设 \(f=(p-1)!\), 则 \(f\equiv a\times A_1\times a\times A_2\times a \times A_3 \dots \times A_{p-1} \pmod p\)
证毕。
也可用归纳法证明:
显然 \(1^p\equiv 1\pmod p\),假设 \(a^p\equiv a\pmod p\) 成立,那么通过二项式定理有
因为 \(\binom{p}{k}=\frac{p(p-1)\cdots (p-k+1)}{k!}\) 对于 \(1\leq k\leq p-1\) 成立,在模 \(p\) 意义下 \(\binom{p}{1}\equiv \binom{p}{2}\equiv \cdots \equiv \binom{p}{p-1}\equiv 0\pmod p\),那么 \((a+1)^p \equiv a^p +1\pmod p\),将 \(a^p\equiv a\pmod p\) 带入得 \((a+1)^p\equiv a+1\pmod p\) 得证。
欧拉定理
在了解欧拉定理(\(\text{Euler's theorem}\))之前,请先了解欧拉函数。定理内容如下:
定义
若 \(\gcd(a, m) = 1\),则 \(a^{\varphi(m)} \equiv 1 \pmod{m}\)。
证明
实际上这个证明过程跟上文费马小定理的证明过程是非常相似的:构造一个与 \(m\) 互质的数列,再进行操作。
设 \(r_1, r_2, \cdots, r_{\varphi(m)}\) 为模 \(m\) 意义下的一个简化剩余系,则 \(ar_1, ar_2, \cdots, ar_{\varphi(m)}\) 也为模 \(m\) 意义下的一个简化剩余系。所以 \(r_1r_2 \cdots r_{\varphi(m)} \equiv ar_1 \cdot ar_2 \cdots ar_{\varphi(m)} \equiv a^{\varphi(m)}r_1r_2 \cdots r_{\varphi(m)} \pmod{m}\),可约去 \(r_1r_2 \cdots r_{\varphi(m)}\),即得 \(a^{\varphi(m)} \equiv 1 \pmod{m}\)。
当 \(m\) 为素数时,由于 \(\varphi(m) = m - 1\),代入欧拉定理可立即得到费马小定理。
扩展欧拉定理
定义
解释
读者可能对第二行产生疑问,这一行表达的意思是:如果 \(b < \varphi(m)\) 的话,就不能降幂了。
主要是因为题目中 \(m\) 不会太大,而如果 \(b < \varphi(m)\),自然复杂度是可以接受的。而如果 \(b \ge \varphi(m)\) 的话,复杂度可能就超出预期了,这个时候我们才需要降幂来降低复杂度。
证明
直观理解
需要知道的是,在 \(\pmod m\) 的条件下,\(a^b \bmod m\) 的取值范围一定在 \([0, m)\),而 \(a^i \bmod m = (a^{i-1} \bmod m) \times a \bmod m\),那么对于任意一个数 \(a\),那么很容易就能知道它的 后继,在有限的空间内这一定会形成一个循环。
在扩展欧拉定理中,循环分为纯循环和混循环。其中纯循环中不存在节点有两个前驱,而混循环则反之。而 \(a^i \mod n\) 形成的序列可以是一个混循环,那么只需要知道循环节的长度,和前面那一小段未进入循环节的长度,就可以根据这个性质来进行降幂了。
值得注意的是,无论是费马小定理,还是(扩展)欧拉定理,一个很重要的应用就是降幂,从而将不可能的表达式化为可能。
形式证明
证明转载自 synapse7,并进行了一些整理。
-
命题:\(a\) 的从 \(0\) 次,\(1\) 次到 \(b\) 次幂模 \(m\) 构成的序列中,存在 \(r\) 和 \(s\),使得前 \(r\) 个数(即从 \(a^0 \bmod m\) 到 \(a^{r-1} \bmod m\))互不相同,从第 \(r\) 个数开始,每 \(s\) 个数就循环一次。
证明:
-
由鸽巢定理易证。
我们把 \(r\) 称为 \(a\) 幂次模 \(m\) 的循环起始点,\(s\) 称为循环长度。(注意:\(r\) 可以为 \(0\))
用公式表述为:\(\forall i \ge r, a^i \equiv a^{i+s} \pmod{m}\)
-
-
命题:\(a\) 为素数的情况,该式成立。
证明:
-
若模 \(m\) 不能被 \(a\) 整除,而因为 \(a\) 是一个素数,那么 \(\gcd(a, m) = 1\) 成立,根据欧拉定理,容易证明该式成立。
-
若模 \(m\) 能被 \(a\) 整除,那么存在 \(r\) 和 \(m'\) 使得 \(m = a^r m'\),且 \(\gcd(a, m')=1\) 成立。所以根据欧拉定理有 \(a^{\varphi(m')} \equiv 1 \pmod{m'}\)。
又由于 \(\gcd(a^r, m')=1\),所以根据欧拉函数的求值规则,容易得到:\(\varphi(m) = \varphi(m') \times (a-1)a^{r-1}\),即我们有:\(\varphi(m') \mid \varphi(m)\)。
所以 \(a^{\varphi(m')} \equiv 1 \pmod {m'}, \varphi(m') \mid \varphi(m) \implies a^{\varphi(m)} \equiv 1 \pmod {m'}\),即 \(a^{\varphi(m)}=km'+1\),两边同时乘以 \(a^r\),得 \(a^{r+\varphi(m)} = km + a^r\)(因为 \(m = a^r m'\))
所以对于 \(m\) 中素因子 \(a\) 的次数 \(r\) 满足:\(a^r \equiv a^{r+\varphi(m)} \pmod m\)。我们可以简单变换形式,得到 推论:
\[b > r \implies a^b \equiv a^{r + ((b-r) \bmod \varphi(m))} \pmod {m} \]又由于 \(m = a^r m'\),所以 \(\varphi(m) = \varphi(a^r) \varphi(m') \ge \varphi(a^r)=a^{r-1}(a-1) \ge r\)(tips:\(a\) 是素数,最小是 \(2\),而 \(r \ge 1\))。
所以因为 \(\varphi(m) \ge r\),故有:
\[a^r \equiv a^{r+\varphi(m)} \equiv a^{r \bmod \varphi(m)+\varphi(m)} \pmod m \]所以
\[\begin{aligned} a^b &\equiv a^{r+(b-r) \bmod \varphi(m)} \\ &\equiv a^{r \bmod \varphi(m) + \varphi(m) + (b-r) \bmod \varphi(m)} \\ &\equiv a^{\varphi(m) + b \bmod \varphi(m)} \end{aligned} \pmod m \]即 \(a^b\equiv a^{b \bmod \varphi(m)+\varphi(m)}\pmod m\)。
-
-
命题:\(a\) 为素数的幂的情况,该式成立。
证明:
-
不妨令 \(a = p^k\),是否依然有 \(\forall r, a^{r} \equiv a^{r+\varphi(m)} \pmod m\)?
答案是肯定的,由命题 1 可知存在 \(s\) 使得 \(a^s\equiv 1 \pmod m\),所以 \(p^{\mathrm{lcm}(s,k)} \equiv 1 \pmod {m}\),所以令 \(s'=\frac{s}{\gcd(s,k)}\) 时,我们能有 \(p^{s'k} \equiv 1 \pmod {m}\)。
此时有关系:\(s' \mid s\) 且 \(s \mid \varphi(m)\),且 \(r'= \lceil \frac{r}{k}\rceil \le r \le \varphi(m)\),由 \(r',s'\) 与 \(\varphi(m)\) 的关系,依然可以得到 \(a^b\equiv a^{b \bmod \varphi(m)+\varphi(m)}\pmod m\)。
-
-
命题:\(a\) 为合数的情况,该式成立。
证明:
-
只证 \(a\) 拆成两个素数的幂的情况,大于两个的用数学归纳法可证。
设 \(a=a_1a_2\),其中 \(a_i=p_i^{k_i}\),而 \(a_i\) 的循环长度为 \(s_i\);
则 \(s \mid \operatorname{lcm}(s_1,s_2)\),由于 \(s_1 \mid \varphi(m),s_2 \mid \varphi(m)\),那么 \(\operatorname{lcm}(s_1,s_2) \mid \varphi(m)\),所以 \(s \mid \varphi(m)\),\(r=\max(\lceil \frac{r_i}{k_i} \rceil) \le \max(r_i) \le \varphi(m)\);
由 \(r,s\) 与 \(\varphi(m)\) 的关系,依然可以得到 \(a^b \equiv a^{b \bmod \varphi(m)+\varphi(m)}\pmod m\)。
证毕。
-
习题
- SPOJ #4141 "Euler Totient Function"[Difficulty: CakeWalk]
- UVa #10179 "Irreducible Basic Fractions"[Difficulty: Easy]
- UVa #10299 "Relatives"[Difficulty: Easy]
- UVa #11327 "Enumerating Rational Numbers"[Difficulty: Medium]
- TIMUS #1673 "Admission to Exam"[Difficulty: High]
乘法逆元
定义
如果一个线性同余方程 \(ax \equiv 1 \pmod b\),则 \(x\) 称为 \(a \bmod b\) 的逆元,记作 \(a^{-1}\)。
如何求逆元
扩展欧几里得法
实现:
void exgcd(int a, int b, int& x, int& y) {
if (b == 0) {
x = 1, y = 0;
return;
}
exgcd(b, a % b, y, x);
y -= a / b * x;
}
扩展欧几里得法和求解线性同余方程是一个原理,在这里不展开解释。
快速幂法
证明
因为 \(ax \equiv 1 \pmod b\);
所以 \(ax \equiv a^{b-1} \pmod b\)(根据费马小定理);
所以 \(x \equiv a^{b-2} \pmod b\)。
然后我们就可以用快速幂来求了。
实现:
int qpow(long long a, int b) {
int ans = 1;
a = (a % p + p) % p;
for (; b; b >>= 1) {
if (b & 1) ans = (a * ans) % p;
a = (a * a) % p;
}
return ans;
}
注意:快速幂法使用了费马小定理,要求 \(b\) 是一个素数;而扩展欧几里得法只要求 \(\gcd(a, b) = 1\)。
线性求逆元
求出 \(1,2,\dots,n\) 中每个数关于 \(p\) 的逆元。
如果对于每个数进行单次求解,以上两种方法就显得慢了,很有可能超时,所以下面来讲一下如何线性(\(O(n)\))求逆元。
首先,很显然的 \(1^{-1} \equiv 1 \pmod p\);
证明:
对于 \(\forall p \in \mathbf{Z}\),有 \(1 \times 1 \equiv 1 \pmod p\) 恒成立,故在 \(p\) 下 \(1\) 的逆元是 \(1\),而这是推算出其他情况的基础。
其次对于递归情况 \(i^{-1}\),我们令 \(k = \lfloor \frac{p}{i} \rfloor\),\(j = p \bmod i\),有 \(p = ki + j\)。再放到 \(\mod p\) 意义下就会得到:\(ki+j \equiv 0 \pmod p\);
两边同时乘 \(i^{-1} \times j^{-1}\):
\(kj^{-1}+i^{-1} \equiv 0 \pmod p\)
\(i^{-1} \equiv -kj^{-1} \pmod p\)
再带入 \(j = p \bmod i\),有 \(p = ki + j\),有:
\(i^{-1} \equiv -\lfloor\frac{p}{i}\rfloor (p \bmod i)^{-1} \pmod p\)
我们注意到 \(p \bmod i < i\),而在迭代中我们完全可以假设我们已经知道了所有的模 \(p\) 下的逆元 \(j^{-1}, j < i\)。
故我们就可以推出逆元,利用递归的形式,而使用迭代实现:
实现:
inv[1] = 1;
for (int i = 2; i <= n; ++i) {
inv[i] = (long long)(p - p / i) * inv[p % i] % p;
}
使用 \(p-\lfloor \dfrac{p}{i} \rfloor\) 来防止出现负数。
另外我们注意到我们没有对 inv[0]
进行定义却可能会使用它:当 \(i | p\) 成立时,我们在代码中会访问 inv[p % i]
,也就是 inv[0]
,这是因为当 \(i | p\) 时不存在 \(i\) 的逆元 \(i^{-1}\)。线性同余方程中指出,如果 \(i\) 与 \(p\) 不互素时不存在相应的逆元(当一般而言我们会使用一个大素数,比如 \(10^9 + 7\) 来确保它有着有效的逆元)。因此需要指出的是:如果没有相应的逆元的时候,inv[i]
的值是未定义的。
另外,根据线性求逆元方法的式子:\(i^{-1} \equiv -kj^{-1} \pmod p\)
递归求解 \(j^{-1}\), 直到 \(j=1\) 返回 \(1\)。
中间优化可以加入一个记忆化来避免多次递归导致的重复,这样求 \(1,2,\dots,n\) 中所有数的逆元的时间复杂度仍是 \(O(n)\)。
注意:如果用以上给出的式子递归进行单个数的逆元求解,目前已知的时间复杂度的上界为 \(O(n^{\frac 1 3})\),具体请看 知乎讨论。算法竞赛中更好地求单个数的逆元的方法有扩展欧几里得法和快速幂法。
线性求任意 n 个数的逆元
上面的方法只能求 \(1\) 到 \(n\) 的逆元,如果需要求任意给定 \(n\) 个数(\(1 \le a_i < p\))的逆元,就需要下面的方法:
首先计算 \(n\) 个数的前缀积,记为 \(s_i\),然后使用快速幂或扩展欧几里得法计算 \(s_n\) 的逆元,记为 \(sv_n\)。
因为 \(sv_n\) 是 \(n\) 个数的积的逆元,所以当我们把它乘上 \(a_n\) 时,就会和 \(a_n\) 的逆元抵消,于是就得到了 \(a_1\) 到 \(a_{n-1}\) 的积逆元,记为 \(sv_{n-1}\)。
同理我们可以依次计算出所有的 \(sv_i\),于是 \(a_i^{-1}\) 就可以用 \(s_{i-1} \times sv_i\) 求得。
所以我们就在 \(O(n + \log p)\) 的时间内计算出了 \(n\) 个数的逆元。
实现:
s[0] = 1;
for (int i = 1; i <= n; ++i) s[i] = s[i - 1] * a[i] % p;
sv[n] = qpow(s[n], p - 2);
// 当然这里也可以用 exgcd 来求逆元,视个人喜好而定.
for (int i = n; i >= 1; --i) sv[i - 1] = sv[i] * a[i] % p;
for (int i = 1; i <= n; ++i) inv[i] = sv[i] * s[i - 1] % p;
逆元练习题
线性同余方程
定义
形如
的方程称为 线性同余方程(\(\text{Linear Congruence Equation}\))。其中,\(a\)、\(b\) 和 \(n\) 为给定整数,\(x\) 为未知数。需要从区间 \([0, n-1]\) 中求解 \(x\),当解不唯一时需要求出全体解。
用逆元求解
首先考虑简单的情况,当 \(a\) 和 \(n\) 互素(\(\text{coprime}\) 或 \(\text{relatively prime}\))时,即 \(\gcd(a, n) = 1\)。
此时可以计算 \(a\) 的逆元,并将方程的两边乘以 \(a\) 的逆元,可以得到唯一解。
证明
接下来考虑 \(a\) 和 \(n\) 不互素(not coprime),即 \(\gcd(a, n) \ne 1\) 的情况。此时不一定有解。例如,\(2x\equiv 1\pmod 4\) 没有解。
设 \(g = \gcd(a, n)\),即 \(a\) 和 \(n\) 的最大公约数,其中 \(a\) 和 \(n\) 在本例中大于 1。
当 \(b\) 不能被 \(g\) 整除时无解。此时,对于任意的 \(x\),方程 \(ax\equiv b\pmod n\) 的左侧始终可被 \(g\) 整除,而右侧不可被 \(g\) 整除,因此无解。
如果 \(g\) 整除 \(b\),则通过将方程两边 \(a\)、\(b\) 和 \(n\) 除以 \(g\),得到一个新的方程:
其中 \(a^{'}\) 和 \(n^{'}\) 已经互素,这种情形已经解决,于是得到 \(x^{'}\) 作为 \(x\) 的解。
很明显,\(x^{'}\) 也将是原始方程的解。这不是唯一的解。可以看出,原始方程有如下 \(g\) 个解:
总之,线性同余方程的 解的数量 等于 \(g = \gcd(a, n)\) 或等于 \(0\)。
用扩展欧几里得算法求解
根据以下两个定理,可以求出线性同余方程 \(ax\equiv b \pmod n\) 的解。
定理 1:线性同余方程 \(ax\equiv b \pmod n\) 可以改写为如下线性不定方程:
其中 \(x\) 和 \(k\) 是未知数。这两个方程是等价的,有整数解的充要条件为 \(\gcd(a,n) \mid b\)。
应用扩展欧几里德算法可以求解该线性不定方程。根据定理 1,对于线性不定方程 \(ax+nk=b\),可以先用扩展欧几里得算法求出一组 \(x_0,k_0\),也就是 \(ax_0+nk_0=\gcd(a,n)\),然后两边同时除以 \(\gcd(a,n)\),再乘 \(b\)。就得到了方程
于是找到方程的一个解。
定理 2:若 \(\gcd(a,n)=1\),且 \(x_0\)、\(k_0\) 为方程 \(ax+nk=b\) 的一组解,则该方程的任意解可表示为:
并且对任意整数 \(t\) 都成立。
根据定理 2,可以从已求出的一个解,求出方程的所有解。实际问题中,往往要求出一个最小整数解,也就是一个特解
其中有
如果仔细考虑,用扩展欧几里得算法求解与用逆元求解,两种方法是等价的。
实现
代码实现:
int ex_gcd(int a, int b, int& x, int& y) {
if (b == 0) {
x = 1;
y = 0;
return a;
}
int d = ex_gcd(b, a % b, x, y);
int temp = x;
x = y;
y = temp - a / b * y;
return d;
}
bool liEu(int a, int b, int c, int& x, int& y) {
int d = ex_gcd(a, b, x, y);
if (c % d != 0) return 0;
int k = c / d;
x *= k;
y *= k;
return 1;
}
本页面主要译自博文 Модульное линейное уравнение первого порядка 与其英文翻译版 Linear Congruence Equation。其中俄文版版权协议为 Public Domain + Leave a Link;英文版版权协议为 CC-BY-SA 4.0。
习题
本文来自博客园,作者:So_noSlack,转载请注明原文链接:https://www.cnblogs.com/So-noSlack/p/18335879