【进阶数论】模乘逆元

【进阶数论】模乘逆元

逆元的定义

\(ax \equiv 1 \pmod{p}\)\(a \perp b\),则称 \(x\)\(a\) 的逆元。记作 \(a^{-1} \pmod{p}\)

同时,我们也可以称 \(x\)\(a\)\(\bmod\ p\) 意义下的倒数。

逆元的求法

裴蜀定理(Bézout's Lemma)

在推导这个定理之前,我们要先了解一下裴蜀定理(Bézout's Lemma)和朴素欧几里得算法

裴蜀定理: 对于任意的 \(a, b\ (a,b\in \Z)\),有 \(x, y\ (x,y\in \Z)\) 使得 \(ax + by = \gcd(a, b)\)

证明

  • 考虑 \(a \perp b\)。这时 \(\gcd(a,b)=1\)。提取 \(\gcd(a,b)\),令 \(g=\gcd(a,b)\) 得:

\[g \left( \frac{a}{g}x + \frac{b}{g}y \right)=1 \]

两个数乘积为 \(1\),要么同为 \(1\),要么同为 \(-1\),因为任何两个数的最大公约数不可能为负数,所以 \(ax + by = \gcd(a, b)=1\)

  • 考虑 \(a\)\(b\) 不互素的情况。此时设 \(g>1\),令 \(a'=\frac{a}{g},b'=\frac{b}{g}\)。所以此时 \(\gcd(a',b')=1\)\(a' \perp b'\)。所以此时有:

\[a'x'+b'y'=1 \]

等式两边同乘以 \(g\),得:

\[ga'x'+ga'y'=g \]

\[ax'+by'=g=\gcd(a,b) \]

\(x=x',y=y'\),得:

\[ax+by=gcd(a,b) \]

多个整数的推广

对于 \(a_1,a_2,a_3,a_4, \cdots , a_n \ (a \in \Z)\)\(x_1,x_2,x_3,x_4, \cdots , x_n \ (x \in \Z)\),令 \(g=\gcd(a_1,a_2,a_3, \cdots a_n)\),有:

\[\sum^{n}_{i=1} a_i \cdot x_i=g \]

【例1】P4549 【模板】裴蜀定理

给定一个包含 \(n\) 个元素的整数序列 \(A\),记作 \(A_1,A_2,A_3,...,A_n\)

求另一个包含 \(n\) 个元素的待定整数序列 \(X\),记 \(S=\sum\limits_{i=1}^nA_i\times X_i\),使得 \(S>0\)\(S\) 尽可能的小。

这就是上述推论的模板。所以答案即为:

\[S_{\min}=\gcd(A_1,A_2,A_3, \cdots ,A_n) \]

那么有一个问题:当 $A_i < 0 $ 如何处理。实际上我们知道,根据上述推论,\(\sum\limits_{i=1}^nA_i\times X_i\) 的值与 \(X_i\) 的值无关。所以我们直接将 \(A_i\) 里的负号移到 \(X_i\) 中。是不影响结果的。也就是说 \(-A_i\) 等价于 \(A_i\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n;
int main() {
	cin>>n;
	ll ans=0,a;
	for(int i=1;i<=n;i++) {
		cin>>a;
		ans=__gcd(ans,abs(a));
	}
	cout<<ans;
}

朴素欧几里得算法(Euclidean algorithm)

\(\gcd(a,b)=\gcd(b , a \bmod b)\)

int gcd(int a,int b){
    if(b==0) return a; 
    return gcd(b,a%b); 
}

当然,C++ 的库函数中有 __gcd() 函数,其时间复杂度与上述代码相同。可以放心使用。

扩展欧几里得算法(Extended Euclidean algorithm)

考虑求 \(ax+by=1\)\(x\) 的最小正整数解。由裴蜀定理证明的第一个过程可知,必须满足 \(a \perp b\)。如果不满足则方程无解。则有如下推导过程:

\[ax+by=1 \]

因为 \(a \perp b\),所以:

\[ax+by=\gcd(a,b) \]

朴素欧几里得定理,得:

\[ax+by=\gcd(b,a \bmod b) \]

裴蜀定理\(ax+by=\gcd(a,b)\),得 \(\gcd(a,b)=ax+by\),即:

\[ax+by=bx'+(a \bmod b)y' \]

根据模运算的定义得:

\[ax+by=bx'+(a - b \left \lfloor \frac{a}{b} \right \rfloor )y' \]

合并同类项,得:

\[ax+by=ay'+b (x' - \left \lfloor \frac{a}{b} \right \rfloor y') \]

所以:

\[\begin{cases} x=y' \\ y=x' - \left \lfloor \frac{a}{b} \right \rfloor y' \end{cases} \]

【例 2】P1082 [NOIP 2012 提高组] 同余方程

求关于 $ x$ 的同余方程 $ a x \equiv 1 \pmod {b}$ 的最小正整数解。

显然这是一个求逆元的题。将 $ a x \equiv 1 \pmod {b}$ 换一种表达方式,得:

\[ax=kn+1 \ (k \in \Z) \]

可以将其化为:

\[ax+kn=1 \]

因此就可以变成扩展欧几里得算法的标准形式:

\[ax+by=1 \]

接下来运用扩欧算法求即可。

但是我们要注意,这个求得的 \(x\) 可能为负数,也有可能不是最小正整数解。

考虑将 \(x\) 转化为符合条件的最小正整数。

有结论:

\[x_{\min}=(x \bmod b + b) \bmod b \]

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll expgcd(ll a,ll b,ll &x,ll &y){
	if (b==0){x=1,y=0; return a;}
	ll p=expgcd(b,a%b,y,x); 
	y-=(a/b)*x;
	return p;
}
ll inv(ll a,ll n){
	ll x,y;
	expgcd(a,n,x,y);   
	x=(x%n+n)%n;  
	return x;
}
int main(){
	ll a,b;
	cin>>a>>b;
	cout<<inv(a,b);
	return 0;
}
posted @ 2025-08-25 21:26  M1_Byte  阅读(16)  评论(0)    收藏  举报