逆元,exgcd,欧拉定理,费马小定理
逆元
定义:如果ax=1(mod p), 则x为a的逆元;
有解条件:a, m互质(也是欧拉定理的前提条件)
应用:求解线性方程ax=b(mod m), 解为:x * b
求逆元方法:
方法一:exgcd
定理:即如果a、b是整数,那么一定存在整数x、y使得ax+by=gcd(a,b)。
换句话说,如果ax+by=m有解,那么m一定是gcd(a,b)的若干倍。(可以来判断一个这样的式子有没有解)
有一个直接的应用就是 如果ax+by=1有解,那么gcd(a,b)=1;
证明:
假设当前我们在求的时a和b的最大公约数,而我们已经求出了下一个状态:b和a%b的最大公因数,并且求出了一组x1和y1使得 b*x1+(a%b)*y1=gcd
(注意在递归算法中,永远都是先得到下面一个状态的值)
这时我们可以试着去寻找这两个相邻状态的关系:
首先我们知道:a%b=a-(a/b)*b;带入:
b*x1 + (a-(a/b)*b)*y1
= b*x1 + a*y1 – (a/b)*b*y1
= a*y1 + b*(x1 – a/b*y1) = gcd 发现 x = y1 , y = x1 – a/b*y1
这样我们就得到了每两个相邻状态的x和y的转化,就可以在求gcd的同时对x和y进行求值了
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 5 using namespace std; 6 7 int exgcd(int a,int b,int &x,int &y)//扩展欧几里得算法 8 { 9 if(b==0) 10 { 11 x=1;y=0; 12 return a; //到达递归边界开始向上一层返回 13 } 14 int r=exgcd(b,a%b,x,y); 15 int temp=y; //把x y变成上一层的 16 y=x-(a/b)*y; 17 x=temp; 18 return r; //得到a b的最大公因数 19 }
方法二:费马小定理/欧拉定理
欧拉定理: 若正整数 a , p 互质,则 aφ(p)≡1(mod p)
费马小定理:若a, p互质且p为质数,则 ap-1=1(mod p)(欧拉定理的特殊形式)
由逆元的定义,ax=1(mod p) (a, p互质),再对比欧拉定理的形式,aφ(p)−1就是a在mod p意义下的逆元。(当p是质数的时候,逆元也就是ap-2)
2、快速幂+费马小定理求逆元(此时a与p互质,且p为质数)
1 LL pow_mod(LL a, LL b, LL p){//a的b次方求余p 2 LL ret = 1; 3 while(b){ 4 if(b & 1) ret = (ret * a) % p; 5 a = (a * a) % p; 6 b >>= 1; 7 } 8 return ret; 9 } 10 LL Fermat(LL a, LL p){//费马求a关于b的逆元 11 return pow_mod(a, p-2, p); 12 }