乘法逆元

定义

如果存在a,x,b满足线性同余方程ax ≡ 1(mod b)(即b除以整数ax − 1,或者换句话说,将ax除以整数b之后的余数为1),则我们称:

a关于模b的乘法逆元为x,表示为a ≡ x-1 (mod b);

x关于模b的乘法逆元为a,表示为x ≡ a-1 (mod b)

附:该运算的基本用途是在可能的情况下求解形式的线性同余ax≡b(mod m)

 

条件

在同余方程中,若a 与b互质, 则一定存在一个正整数解x, 满足x < b;若a 与b 不互质, 则一定不存在正整数解x.所以逆元要求a与b互质。

 

 

求解

扩展欧几里得

扩展欧几里得算法是用来解决:ax+by = gcd(a,b),求x和y的问题。我们的逆元式子为ax ≡ 1(mod b),求x,根据它的实际定义,我们首先可以表示为

ax%b=1

接着变换为

ax-by=1

 假设y<0

ax+by=1

这样我们就能够利用扩展欧几里得算法求解了。

例如 7x=1(mod 4),求x

def ext_euclid(a, b):
    if b == 0:
        return 1, 0
    else:
        x, y= ext_euclid(b, a % b)
        x, y = y, (x - (a // b) * y)
        return x, y
x,y = ext_euclid(7,4)
print (x,y)

 

快速幂法

在ab ≡ 1(mod p)中求解

这个要运用费马小定理 :

若p为质数,a为正整数,且 a、p互质,则ap-1≡1(mod p)。

因为ax ≡ 1(mod b)

所以ax ≡ ab-1(mod b)(根据费马小定理)

所以x ≡ ab-2(mod b)

然后我们就可以用快速幂来求了。

inline int qpow(long long a, int b) {
  int ans = 1;
  a = (a % p + p) % p;
  for (; b; b >>= 1) {
    if (b & 1) ans = (a * ans) % p;
    a = (a * a) % p;
  }
  return ans;
}

 

线性求逆元

例:ab ≡ 1(mod p),求b

p%a = p-(p/a)*a;  在c++中/为整除

(p/a)*a = p-(p%a);  换下位置

(p/a)*a = -(p%a);  在模p意义下p可以约掉,可以没有这一步

a = -(p%a)/(p/a);  再换一下位置

a-1 = -(p%a)-1*(p/a);

所以a-1可以用(p%a)-1推出,所以就可以用递推式来推出1到a的所有数的逆元。

求解多个逆元

int inv[MAXN]; 
void INV(int a,int p)//线性求到a的逆元 
{
    inv[1] = 1;
    for (int i=2; i<=a; ++i)
        inv[i] = (-(p/i))*inv[p%i]%p; 
}

求解一个逆元

int INV(int a)//线性求a的逆元 
{
    if (a==1) return 1;
    return ((-(p/a)*INV(p%a))%p);
}

 

参考

https://oi-wiki.org/math/inverse/

https://www.cnblogs.com/mjtcn/p/7241896.html

https://oi-wiki.org/math/linear-equation/

https://en.wikipedia.org/wiki/Modular_multiplicative_inverse

 

原文地址:https://www.cnblogs.com/Mayfly-nymph/p/12393324.html