同余式ax≡c(mod m)的求解:扩展欧几里得——解ax+by = c、ax≡c(mod m)
以下部分整理自—《算法笔记》胡凡、曾磊
什么是逆元
逆元:假设a、b、m是整数,m>1,且有ab≡1(mod m)成立,那么就说a和b互为模m的逆元,一般也记做a≡
1
b
\frac {1} {b}
b1(mod m) 或b≡
1
a
\frac {1} {a}
a1(mod m) 。通俗地说如果两个整数的乘积模m后等于1,就称它们互为m的逆元。
用处:取模运算:
(
a
+
b
)
%
m
o
d
=
(
a
%
m
o
d
+
b
%
m
o
d
)
%
m
o
d
(a+b)\%mod=(a\%mod+b\%mod)\%mod
(a+b)%mod=(a%mod+b%mod)%mod
(
a
−
b
)
%
m
o
d
=
(
a
%
m
o
d
−
b
%
m
o
d
+
m
o
d
)
%
m
o
d
(a−b)\%mod=(a\%mod−b\%mod+mod)\%mod
(a−b)%mod=(a%mod−b%mod+mod)%mod
(
a
∗
b
)
%
m
o
d
=
(
a
%
m
o
d
∗
b
%
m
o
d
)
%
m
o
d
(a∗b)\%mod=(a\%mod∗b\%mod)\%mod
(a∗b)%mod=(a%mod∗b%mod)%mod
但是:
(
a
/
b
)
%
p
=
(
a
%
p
/
b
%
p
)
%
p
(a/b)\%p=(a\%p/b\%p)\%p
(a/b)%p=(a%p/b%p)%p却不成立!!!
例如:
(
6
/
2
)
%
2
=
1
,
(
6
%
2
/
3
%
2
)
%
2
=
0
(6/2) \% 2=1 , (6\%2/3\%2)\%2=0
(6/2)%2=1,(6%2/3%2)%2=0
这时候就需要逆元来计算(b/a)%m。通过找到a模m的逆元x,就有(b/a)%m=(b
∗
*
∗x)%m成立(这里只考虑b%a=0的情况),于是就把除法取模转化为乘法取模
(或者推导如下:(b/a)%m=(b/a)%m
∗
*
∗(a
∗
*
∗x)%m=((b/a)
∗
*
∗ax)%m=(b
∗
*
∗x)%m)
//因为很多时候取模运算中还有除法,先计算除法部分又比较困难,我们就把除法A/B转化为另一个模m后结果相同的数,即A*inv(B),也就引入了逆元
扩展欧几里得
由定义可知,求a模m的逆元,就是求解同余式ax≡1(mod m)。
并且在扩展欧几里得在求解实际问题中,一般把x的最小整数解称为a模m的逆元。而且同余式ax≡1(mod m)要有解,就要满足gcd(a,m)=1,即gcd(a,m)|1。
(gcd(a, b) | d,表示d能整除gcd,这个符号在数学上经常见)
欧拉定理(费马小定理)
一个关于同余性质的定理,若n,a为正整数,且n,a互质,则:
φ
(
n
)
φ(n)
φ(n)是1~n的数中与n互质的数的数目,即欧拉函数,我们记为
φ
(
n
)
φ(n)
φ(n)。此函例如
φ
(
8
)
=
4
φ(8)=4
φ(8)=4,因为1,3,5,7均和8互质。
欧拉函数的求解:求欧拉函数值 && 打表O(n)
通过这个定理,我们就可以用aφ(p)-1来表示a关于p的逆元,其中a φ(p)-1可以用快速幂求解
注:欧拉定理求得的逆元结果和上面用扩展欧几里得求得的最小正整数解不一定相等,一个数的逆元不止一个。
另外,若p为素数,此时很明显 φ ( p ) φ(p) φ(p)等于p-1,那么就会满足下面的式子ap-1≡1(mod p),这就是费马小定理
线性求逆元O(n)(打表)
我们要求要求1~p−1的数关于p的逆元
公式: i n v [ i ] = ( p − p / i ) ∗ i n v [ p % i ] % p inv[i]=(p-p/i)*inv[p\%i]\%p inv[i]=(p−p/i)∗inv[p%i]%p
要求
i
i
i关于
p
p
p的逆元,
p
p
p可以写成
p
=
k
i
+
r
p=ki+r
p=ki+r
∴
k
i
+
r
=
0
(
m
o
d
p
)
ki+r=0(mod\ p)
ki+r=0(mod p)
为了后面不用考虑负数取模的问题,同时方便结果式的表达,我们把上式写为:
k
i
+
r
=
p
i
(
m
o
d
p
)
ki+r=pi(mod\ p)
ki+r=pi(mod p)
∴
r
=
p
i
−
k
i
(
m
o
d
p
)
r=pi-ki(mod\ p)
r=pi−ki(mod p)
两边同时乘以
i
、
r
i、r
i、r的逆元inv(i)、inv(
r
r
r)得到:
r
∗
i
n
v
(
i
)
∗
i
n
v
(
r*inv(i)*inv(
r∗inv(i)∗inv(r
)
=
(
p
i
−
k
i
)
∗
(
i
n
v
(
i
)
∗
i
n
v
(
)=(pi-ki)*(inv(i)*inv(
)=(pi−ki)∗(inv(i)∗inv(r
)
)
(
m
o
d
p
)
))(mod p)
))(modp)
∴
i
n
v
(
i
)
=
(
p
−
k
)
∗
i
n
v
(
inv(i)=(p-k)*inv(
inv(i)=(p−k)∗inv(r
)
)
)
代入
k
=
p
/
i
,
r
=
p
%
i
k=p/i,r=p\%i
k=p/i,r=p%i得到:
i
n
v
(
i
)
=
(
p
−
p
/
i
)
∗
i
n
v
(
p
%
i
)
inv(i)=(p-p/i)*inv(p\%i)
inv(i)=(p−p/i)∗inv(p%i)
代码:
//MOD大于n
inv[1]=1;
for(int i=2;i<=n;++i)
inv[i]=MOD-(long long)MOD/i*inv[MOD%i]%MOD;