逆元:
方程 ax≡1(mod p) 的解称为a关于模p的逆,当gcd(a,p)==1(即a,p互质)时,方程有唯一解,否则无解。
也就是说一个数有逆元的充分必要条件是gcd(a,n)=1,此时逆元唯一存在 。
有
(a+b)%c=(a%c+b%c)%c
(a*b)%c=(a%c*b%c)%c
(a-b)%c=(a%c-b%c)%c
但是却没有 (a/b)%c=(a%c/b%c)%c , 这是错的 , 但是我们可以将它转化成乘法。
令inv(x)表示的是某个数的逆元。
那么该式就可以改成 ( a / b ) % c = ( a * inv(b) )% c = ( a % m * inv(b) % m ) % m;
1.用扩展欧几里得求逆元
咳咳。。。为什么要用扩展欧几里得求逆元?
什么是扩展欧几里得?
//扩展欧几里得法求逆元
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll ExEculid(ll a , ll b , ll &x , ll &y)
{
if(b == 0)
{
x = 1; y = 0;
return a;
}
ll tx , ty;
ll d = ExEculid(b , a % b , tx , ty);
x = ty;
y = tx - (a/b)*ty;
return d;
}
ll inv(ll a , ll n)//模 n 下 a 的逆元
{
ll x , y;
ll d = ExEculid(a , n , x , y);//必要条件 gcd(a , n) = 1;
return d == 1 ? (x + n) % n : -1;//无则返回-1
//(x + n) % n 这样写的原因是防止x为负数
}
int main()
{
int a , n;
while(cin >> a >> n)
cout << inv(a , n) << endl;
return 0 ;
}
2 . 用费马小定理求逆元
什么是费马小定理??
假如p是质数,且gcd(a,p)=1,那么 a^(p-1)≡1(mod p)
看到这样一个式子是不是可以很容易想到 a * a^(p-2) ≡ 1(mod p) , 那么a ^(p-2) 就是模p下 a 的逆元了。
推导过程:
如果这个数很大很大自然可以想到用快速幂来求解a ^(p-2)
下面代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll qpow(ll a , ll b , ll m)//快速幂
{
ll ans = 1;
a %= m;
while(b)
{
if(b & 1)
{
ans = ans * a % m;
}
a = a * a % m;
b = b / 2;
}
return ans;
}
ll Fermat(ll a , ll p)//费马小定理求 a ^(p-2)
{
return qpow(a , p-2 , p);
}
int main()
{
ll a , b;
cin >> a >> b;
cout << Fermat(a , b) << endl;
return 0;
}
例子!!一看就懂!!!
如果还是不太懂逆元是怎么一回事 , 可以看看这个例子:
很明显看出(18 / 3)% 5 的答案是 1。
但是如果前面的数不是18 而是一个很大很大的数的连longlong都存不下呢?
我们肯定是一边乘一边求mod。
首先可以将这个式子转变为(18 % 5 * inv(3) % 5 ) % 5.
费马小定理: inv(3) = 3 ^ (5 - 2) = 27 ===》(3 * 27 ) % 5 = 1.
扩展欧几里得:inv(3) = ExEculid( 3 ,5 , x , y) 中 x 的值 , 这里x = 2 ===》( 3 * 2 ) % 5 = 1.
这样就结束了~ 所以好像说了这么多 , 其实就只是为了实现除法的同余解法