乘法逆元

乘法逆元

需要乘法逆元的原因:对于两个超大的正整数a, b, long long无法存储,保证b | a, 现在要计算(a / b) mod m,其中m为素数。考虑以下计算方法:

认为\(a / b = (a \%m) / (b \% m) \%m\),这个显然不对。

所以为了能够方便的算出(a / b) mod m, 就出现了能够将(a / b) mod m 转化为(a * x) mod m的方法,其中x就是b在mod m意义下的逆元。

设存在一个数x,能够使得\(b * x \equiv 1 (mod \ m)\)

  1. b和m不互质,即b和m之间存在除了1以外的公约数:因为m为素数,所以m的因数只有1和m,而b和m之间有除了1以外的其他公约数,那么这个公约数必定是m,即b % m = 0,即b是m的倍数,所以b * x是m的倍数,所以b * x % m永远不不可能为1,即此方程无解。
  2. b和m互质。

对于第二种情况:

费马小定理\(p\)为质数\((p\ge 2)\)\(a\)为任意自然数,则\(a^p\equiv a(mod \ p)\)

当且仅当a与模数p互质时,因为p是质数,所以必定有a % p ≠ 0的,所以在模p的意义下,可以将方程两边同时约去a得到

\[a^{p - 1}\equiv 1(mod \ p) \]

进一步将方程左侧拆开得到

\[a * a^{p - 2} \equiv 1(mod \ p) \]

所以当b和m互质的时候,由费马小定理可以得到\(b * x \equiv 1(mod \ m)\)必有解,解就是\(b^{m-2}\),而它就是b在mod m意义下的乘法逆元。

\(b * x \equiv 1 (mod \ m)\)的解来作为b的乘法逆元的原因如下:

\((a / b) \% m\)

\(= (a / b) * b * x \% m\)(其中x为b在mod m意义下的乘法逆元,有b * x % m = 1)

\(=a * x \% m\)

通过\(b * x \equiv 1 (mod \ m)\)\((a / b) \% m\)转为了\(a * x \% m\).

计算

由于这个素数m可能很大,所以\(x = b^{m - 2}\)可能非常大。

因为\(b * x \equiv 1 (mod \ m)\)

所以有\(b * (x \% m) \equiv 1 (mod \ m)\)

\(x \% m\)同样是b的乘法逆元。

所以只需计算\(b^{m - 2} \% m\)

这里用快速幂。

给定\(n\)\(a_i,p_i\)其中\(p_i\)是质数,求\(a_i\)\(p_i\)的乘法逆元,若逆元不存在则输出impossible。

注意:请返回在\(0∼p−1\)之间的逆元。

#include<iostream>
using namespace std;

#define LL long long

int n;
int a, p;

LL quick_pow(int a, int b, int p){
    LL res = 1, base = a;
    while(b){
        if(b & 1) res = (res * base) % p;
        base = (base * base) % p;
        b >>= 1;
    }
    
    return res;
}

int main(){
    cin >> n;
    
    while(n --){
        cin >> a >> p;
        
        if(a % p == 0){
            puts("impossible");
            continue;
        }
        
        cout << quick_pow(a, p - 2, p) << endl;
    }
    
    return 0;
}
posted @ 2020-12-31 21:09  yys_c  阅读(122)  评论(0)    收藏  举报