逆元定义:方程ax≡1(mod p),的解称为a关于模p的逆,当gcd(a,p)==1(即a,p互质)时,方程有唯一解,否则无解。
一.扩展欧几里得求解
证明如下:
a*x + b*y = 1
如果ab互质,才有解
这个解的x就是a关于b的逆元
y就是b关于a的逆元
为什么呢?
两边同时求余b
a*x % b + b*y % b = 1 % b
a*x % b = 1 % b
a*x = 1 (mod b)
所以x是a关于b的逆元
反之可证明y
条件: a,p互质才能使用
#include<cstdio>
typedef long long LL;
void ex_gcd(LL a, LL b, LL &x, LL &y, LL &d){
if (!b) {d = a, x = 1, y = 0;}
else{
ex_gcd(b, a % b, y, x, d);
y -= x * (a / b);
}
}
LL inv(LL t, LL p)
{//如果不存在,返回-1
LL d, x, y;
ex_gcd(t, p, x, y, d);
return d == 1 ? (x % p + p) % p : -1;
}
int main(){
LL a, p;
while(~scanf("%lld%lld", &a, &p)){
printf("%lld\n", inv(a, p));
}
}
二.费马小定律求逆元
证明如下:
费马小定律:假如p是质数,且gcd(a,p)=1,那么 a^(p-1)≡1(mod p)
由费马小定律我们可以想到是不是很像逆元的形式,即:
a*a^(p-2)≡1(mod p)
也就是说a^(p-2)是a的逆元。
条件:p是质数,且a不能被p整除!!(费马小定律成立条件),复杂度O(log2(p))
#include<bits/stdc++.h>
#define ll long long
using namespace std;
//前提条件 p是质数,a不能被p整除
ll power_mod(ll a, ll b, ll mod)
{
ll ans = 1;
while (b)
{
if (b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
int main(){
ll a, p;
while(~scanf("%lld%lld", &a, &p))
{
if(a%p==0)
printf("-1\n");
else
printf("%lld\n", power_mod(a,p-2,p));
}
}
三.费马小定律扩展(用欧拉定律求逆元)
当p不是质数时就不能使用费马小定律了。
其中φ(n)表示1~n中与n互质的数按顺序排布:x1,x2……xφ(n) (显然,共有φ(n)个数)
其实就是求出φ(p)后,与前面费马小定律的步骤一模一样。
四.用一般方法
注意这种方法不是用来求逆元的,而是用来化简(a/b)%p的
先介绍一下结论
证明