最近,wyb小朋友老是不好好搞他的数据结构,跑过来问我数学,没办法,所以我决定每天发一篇数论的博客,骗骗流量(以后wyb有不会的就看我博客,哈哈哈)先从基础的更起吧。
我第一次接触逆元是在离散数学的代数系统中,对于一种运算满足(为该运算的单位)则称是的逆元。
逆元在算法中主要是为了整数的除法取模,显然除法是不能直接取模的。但是我们可以转化一下,因为乘法是可以直接取模的。
所以我们的问题直接转变成了求b的逆元。
(此处的p为素数)
要证明费马小定理,首先我们需要证明对于任意的整数a,b,c有一个素数p满足,使得
对p取模的所有数字为,又因为0乘任何数等于0所以剔除0,令a为任意正整数都有原式得证
如果p为小素数我们选择直接暴力,时间复杂度为:
int Fermat_inverse(int a,int mod)
{
int res = 1;
for(int i = 1;i < mod - 1;++i) res *= a;
return res;
}
如果p为大素数,我们可以用快速幂求解,时间复杂度为:
long long fast_pow_mod(long long a,long long b,long long mod)
{
long long res = 1;
while(b){
if(b & 1) res = (res * a) % mod;
a = (a * a) % mod;
b >>= 1;
}
return res;
}
long long Fermat_inverse(long long a,long long mod)
{
return fast_pow_mod(a,mod - 2,mod);
}
对于任意的两个正整数(负整数将负号提至系数)a,b必然存在两个整数x,y使得
懒得再写一篇。
设,所以显然存在两个整数x,y使得
int extend_gcd(int a,int b,int &x,int &y)
{
if(!b){
x = 1,y = 0;
return a;
}
else{
int t = extend_gcd(b,a % b,y,x)
y -= (a / b) * x;
return t;
}
}
至于取逆元:
int inverse_extend_gcd(int n)
{
int x,y;
gcd_plus(n,mod,x,y);
x = (x % mod + mod) % mod;
return x;
}
费马定理指出:
所以此处模运算的逆元为
所以只需要打出欧拉表就能的求出逆元啦。