1.乘法逆元的定义及作用
定义(口胡):
乘法逆元是取模运算中的一个东西。假设
a
x
≡
1
(
m
o
d
p
)
ax≡1 (mod p)
ax≡1(modp) 并且GCD(a,p)=1 (a,p互质),那么x就是a的逆元。对于给定的a和p,有且仅有一个数是它的逆元。
乘法逆元的作用:
因为取模这个运算是不满足“除法分配率”的,这就导致了如果a,b或者p很大的话,
(
a
b
)
m
o
d
p
(\frac a b) \mod p
(ba)modp 这个运算就会爆精度。那么我们就要用另外一种方法来计算这个式子,而乘法逆元给我们提供了一个很好的途径。
(
a
b
)
m
o
d
p
=
(
a
b
)
∗
1
m
o
d
p
=
(
a
b
)
∗
(
b
∗
x
)
m
o
d
p
=
a
∗
x
m
o
d
p
(
x
为
b
的
逆
元
时
)
(\frac a b) \mod p = (\frac a b)*1 \mod p = (\frac a b)* (b*x) \mod p =a*x \mod p (x为b的逆元时)
(ba)modp=(ba)∗1modp=(ba)∗(b∗x)modp=a∗xmodp(x为b的逆元时)
这样我们就把除法变成满足Mod分配率的乘法了。
##2.乘法逆元的求法
1.扩展欧几里德求逆元
什么是扩展欧几里德
此时a,p一定要满足互质
对于式子 ax≡1 (mod p) 我们可以将它变成一个方程:
a
∗
x
+
p
∗
y
=
1
a*x+p*y=1
a∗x+p∗y=1
由于我们前面定义中说明了
G
C
D
(
a
,
p
)
=
1
GCD(a,p)=1
GCD(a,p)=1,此时由于裴蜀定理,该方程一定至少有一组解。我们可以用扩展欧几里德算法求得特殊解,再套用通解公式:
y
=
y
0
−
a
G
C
D
(
a
,
b
)
∗
t
y=y0-\frac a {GCD(a,b)}*t
y=y0−GCD(a,b)a∗t求出满足mod p条件的一组解(也就是mod一下啦)
代码如下:
int exgcd(int a,int b,int &x,int &y){
if (b==0) {x=1,y=0; return x;}
int ret=exgcd(b,a%b,x,y);
int t=x; x=y,y=t-a/b*y;
return ret;
}
int calc(int n,int p){
int pd=exgcd(n,p,x,y);
if (pd==1) return (x%p+p)%p;
}
2.费马小定理求逆元
首先了解一下费马小定理:
p是素数时,对于任意整数x都有
x
p
≡
x
(
m
o
d
p
)
x^p ≡ x (mod p)
xp≡x(modp)。
如果x为整数且x,p互质,则有
x
p
−
1
≡
1
(
m
o
d
p
)
x^{p−1} ≡ 1 (mod p)
xp−1≡1(modp)。
证明详见百度百科:传送门
那么就可以来推导了:
x
p
−
1
≡
x
∗
x
p
−
2
≡
1
(
m
o
d
p
)
x^{p−1} ≡ x*x^{p-2} ≡ 1 (mod p)
xp−1≡x∗xp−2≡1(modp)。那么根据乘法逆元的定义可以得到x的逆元就是
x
p
−
2
x^{p-2}
xp−2。求
x
p
−
2
x^{p-2}
xp−2只要用一下快速幂就好了。当然成立的条件是满足x,p互质。
代码如下:
int qsm(int x,int y){
int ans=1,w=x;
while (y) {
if (y%2==1) ans=(ans*w)%p;
y/=2; w=(w*w)%p;
}
return ans;
}
int calc(int n,int p){
return qsm(n,p-2);
}
3.欧拉函数求逆元
欧拉定理:对于两个互质的正整数a,p(p>2)有:
x
φ
(
p
)
≡
1
(
m
o
d
p
)
x^φ(p) ≡ 1(mod p)
xφ(p)≡1(modp)。
变形一下就可以得到:
x
∗
x
(
φ
(
p
)
−
1
)
≡
1
(
m
o
d
p
)
x*x^{(φ(p)-1)} ≡ 1(mod p)
x∗x(φ(p)−1)≡1(modp)
那么我们就可以先求出欧拉函数值φ§然后快速幂就能够解决了。
这种方法成立的条件同样是要满足x,p互质。
注:
欧拉函数:
φ
(
x
)
=
x
(
1
−
1
p
(
1
)
)
(
1
−
1
p
(
2
)
)
(
1
−
1
p
(
3
)
)
…
.
.
(
1
−
1
p
(
n
)
)
(
p
(
i
)
表
示
x
的
第
i
个
质
因
子
)
φ(x)=x(1-\frac 1 {p(1)})(1-\frac 1 {p(2)})(1-\frac1 {p(3)})…..(1-\frac1 {p(n)})(p(i)表示x的第i个质因子)
φ(x)=x(1−p(1)1)(1−p(2)1)(1−p(3)1)…..(1−p(n)1)(p(i)表示x的第i个质因子)
证明详见我的另一篇blog:传送门
代码如下:
int qsm(int x,int y){
int ans=1,w=x;
while (y) {
if (y%2==1) ans=(ans*w)%p;
y=y /2; w=(w*w)%p;
}
return ans;
}
int geteular(int num){
int ret=num,x=num;
for (int i=2;i*i<=num;i++)
if (x%i==0) {
ret=ret*(i-1)/i;
while (!x%i) x/=i;
}
if (x>1) ret=ret*(x-1)/x;
return ret;
}
int calc(int n,int p){
int p1=geteular(p);
return qsm(n,p1-1);
}
4.线性求逆元
当模数p比较小(可以用数组存储时)就可以线性求出范围内所有数的逆元。
我们来推导一下:
1
−
1
≡
1
(
m
o
d
p
)
1^{−1}≡1 (mod p)
1−1≡1(modp)
设
p
=
k
∗
x
+
m
p=k*x+m
p=k∗x+m
带入
m
o
d
p
mod p
modp的式子中:
k
∗
x
+
m
≡
0
(
m
o
d
p
)
k*x+m≡0 (mod p)
k∗x+m≡0(modp)
两边同乘
x
−
1
∗
p
−
1
x^{−1}*p^{−1}
x−1∗p−1就能得到:
k
∗
m
−
1
+
x
−
1
≡
0
(
m
o
d
p
)
k*m^{−1} + x^{−1}≡0 (mod p)
k∗m−1+x−1≡0(modp)
x
−
1
≡
−
k
∗
m
−
1
(
m
o
d
p
)
x^{−1}≡−k*m^{−1} (mod p)
x−1≡−k∗m−1(modp)
x
−
1
≡
−
(
p
x
)
∗
(
p
m
o
d
x
)
−
1
(
m
o
d
p
)
x^{−1}≡-(\frac p x) * (p \mod x)^{−1} (mod p)
x−1≡−(xp)∗(pmodx)−1(modp)
那么就可以递推处理了。
代码如下:
for(int i=2;i<maxn;i++) inv[i]=(-p/i+p)*inv[p%i]%p;
##3.几个模版题
LG p3811
今天就写到这里,如果想到什么再补充。。。
Update 2018.7.20 加了一些latex公式,大大增强了可读性