数论初步:乘法逆元与几种求法

1.乘法逆元的定义及作用
定义(口胡):
乘法逆元是取模运算中的一个东西。假设 a x ≡ 1 ( m o d p ) ax≡1 (mod p) ax1(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)(bx)modp=axmodpxb
这样我们就把除法变成满足Mod分配率的乘法了。

##2.乘法逆元的求法
1.扩展欧几里德求逆元

什么是扩展欧几里德
此时a,p一定要满足互质
对于式子 ax≡1 (mod p) 我们可以将它变成一个方程: a ∗ x + p ∗ y = 1 a*x+p*y=1 ax+py=1
由于我们前面定义中说明了 G C D ( a , p ) = 1 GCD(a,p)=1 GCDap=1,此时由于裴蜀定理,该方程一定至少有一组解。我们可以用扩展欧几里德算法求得特殊解,再套用通解公式: y = y 0 − a G C D ( a , b ) ∗ t y=y0-\frac a {GCD(a,b)}*t y=y0GCD(a,b)at求出满足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) xpx(modp)
如果x为整数且x,p互质,则有 x p − 1 ≡ 1 ( m o d p ) x^{p−1} ≡ 1 (mod p) xp11(modp)
证明详见百度百科:传送门
那么就可以来推导了: x p − 1 ≡ x ∗ x p − 2 ≡ 1 ( m o d p ) x^{p−1} ≡ x*x^{p-2} ≡ 1 (mod p) xp1xxp21(modp)。那么根据乘法逆元的定义可以得到x的逆元就是 x p − 2 x^{p-2} xp2。求 x p − 2 x^{p-2} xp2只要用一下快速幂就好了。当然成立的条件是满足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) xx(φ(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(1p(1)1)(1p(2)1)(1p(3)1)..(1p(n)1)p(i)xi
证明详见我的另一篇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) 111(modp)
p = k ∗ x + m p=k*x+m p=kx+m
带入 m o d p mod p modp的式子中:
k ∗ x + m ≡ 0 ( m o d p ) k*x+m≡0 (mod p) kx+m0(modp)
两边同乘 x − 1 ∗ p − 1 x^{−1}*p^{−1} x1p1就能得到:
k ∗ m − 1 + x − 1 ≡ 0 ( m o d p ) k*m^{−1} + x^{−1}≡0 (mod p) km1+x10(modp)
x − 1 ≡ − k ∗ m − 1 ( m o d p ) x^{−1}≡−k*m^{−1} (mod p) x1km1(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) x1(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公式,大大增强了可读性

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页