Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

逆元的理解

数论中的逆元即数论倒数,既一个正整数a,存在另一个正整数x使得a×x1(modp)a\times x≡1(\mod p)(其中a与p互素),则称x为a的一个关于p的逆元。

逆元的由来

为什么要有逆元这个说法呢,类比到矩阵中去,在矩阵乘法中,两个乘积为单位矩阵的矩阵,其中一个矩阵就是另一个矩阵的逆矩阵,这样就解决了矩阵中没有定义除法的问题。

而类似的,在数论中也没有除法的相关定义(学过线代会知道整数集对于除法是不封闭的),于是我们就思考如何将乘法转换为除法(参考实数集中的分数)。

再来举几个取模中的例子来说明一下:

再取模运算的规律中,有如下几个定义:

(a+b)modp=(amodp+bmodp)modp(a + b) \mod p = (a\mod p + b\mod p) \mod p

(ab)modp=(amodpbmodp)modp(a - b) \mod p = (a\mod p - b\mod p) \mod p

$(a \times b) \mod p = (a\mod p \times b\mod p) \mod p $

为什么其中没有定义除法相关的取模运算呢?

来举个例子

对于(100/50)mod20(100/50)\mod 20来说,结果应该是2;

那么如果使用上述定义的方法来计算这个值,也就是((100mod20)/(50mod20))mod20((100\mod 20) /(50\mod 20))\mod 20
那么结果应该是0,显然是矛盾的,也就是说对于除法来说,取模运算时非常复杂的,而在计算机中,通常需要计算两个很大的数字相除的时候,是存不下的,但这个时候又不能使用取模公式使分子和分母变小,于是就有了逆元

逆元的概念

在实数集中我们如何将除法转化为乘法呢,我们定义了分数,也就是

a×x=1a\times x=1,就令x=1/ax=1/a,如果a不为1,x就为小数。

而在数论中要考虑的问题就变成了a×x1(modp)a\times x≡1(\mod p),而这里的x还是1/x嘛?答案是不是,举个例子:

2×3mod5=12\times 3\mod 5=1

所以逆元也叫数论倒数。这里我们令x=inv(a,p)x=inv(a,p),也就是表示a模p运算时的逆元。

那么我们再来思考这个问题(a/b)modp(a/b)\mod p要如何来转化,我们先将除法变为乘法,也就是(a×inv(a,p))modp(a\times inv(a,p))\mod p

于是我们就能使用乘法公式进行展开,变为(amodp×inv(a,p)modp)modp(a\mod p\times inv(a,p)\mod p)\mod p,于是我们缩小a的目的就达到了。

下面介绍如何计算逆元

逆元的计算

首先明确只有当a与p互质时,a才存在关于p的逆元。求逆元的方法主要时利用费马小定理和拓展欧几里得定理

费马小定理

证明

数论四大定理中的费马小定理是这样定义的:

ap11(modp)a^{p-1}≡1(\mod p),其中p为素数,a与p互素。

那么我们两边同时乘以a关于p的逆元,也就得到了ap1×inv(a,p)inv(a,p)(modp)a^{p-1} \times inv(a,p)≡inv(a,p)(\mod p)

于是由逆元的性质得到了逆元的计算方法:

ap2inv(a,p)(modp)a^{p-2}≡inv(a,p)(\mod p)

也就是ap2=inv(a,p)(modp)a^{p-2}=inv(a,p)(\mod p),再使用一次快速幂就能得到逆元了

代码

1
2
3
4
5
6
7
8
9
10
11
12
LL pow_mod(LL a, LL b, LL p){//a的b次方求余p 
LL ret = 1;
while(b){
if(b & 1) ret = (ret * a) % p;
a = (a * a) % p;
b >>= 1;
}
return ret;
}
LL Fermat(LL a, LL p){//费马求a关于b的逆元
return pow_mod(a, p-2, p);
}

拓展欧几里得算法

当a,b互质的时候,贝祖定理得到的结果应该是长这样的:

a×x+b×y=1a\times x+b\times y=1

贝祖定理证明了这个式子是有解的。接下来我们让两边同时取模b,得到:

a×xmodb+b×ymodb=1modba\times x\mod b+b\times y\mod b=1\mod b

也就是

a×xmodb=1modba\times x\mod b=1\mod b

于是得到同余方程:

a×x1(modb)a\times x≡1(\mod b)

于是x就是inv(a,b)。于是就能通过拓展欧几里得算法,求出x。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include<cstdio>
typedef long long LL;
void ex_gcd(LL a, LL b, LL &x, LL &y, LL &d){
if (!b) {d = a, x = 1, y = 0;}
else{
ex_gcd(b, a % b, y, x, d);
y -= x * (a / b);
}
}
LL inv(LL t, LL p){//如果不存在,返回-1
LL d, x, y;
ex_gcd(t, p, x, y, d);
return d == 1 ? (x % p + p) % p : -1;
}
int main(){
LL a, p;
while(~scanf("%lld%lld", &a, &p)){
printf("%lld\n", inv(a, p));
}
}

参考链接

境外之主

评论