逆元,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  }

 

posted @ 2019-08-26 15:57  滚烫的青春  阅读(323)  评论(0编辑  收藏  举报