逆元入门总结

前言:

1.何为乘法逆元?
对于两个数a,p,若gcd(a,p)=1,则一定存在另一个数b,使得ab≡1(modp),并称此时的b为a关于1模p的乘法逆元。我们记此时的b为inv(a)或a^-1

举个例子:5×3≡1(mod14),我们称此时的3为5关于1模14的乘法逆元。

2.乘法逆元的作用?
我们由费马小定理可得:a*a^(−1)≡a*a^(p−2)≡1 (mod p)

所以:
a^(p−2)≡a^(−1)≡1/a (mod p)
我们又知道模运算的乘法结合律:
b/a≡b⋅a^(−1)≡b⋅a^(p−2) (mod p)

所以我们可以知道:a除以一个数模p,等于a乘这个数的乘法逆元模p。

 

如何求乘法逆元?

1.费马小定理(因为费马小定理的前提 就是 p为质数)

a^(p-1) ≡1 (mod p)

两边同除以a

a^(p-2) ≡1/a (mod p)

什么?这可是数论,还敢写1/a

应该写a^(p-2) ≡ inv(a) (mod p)

所以inv(a) = a^(p-2) (mod p)

由费马小定理 a^(p-1)≡1 , 变形得 a*(a^(p-2))≡1(mod p),

若a,p互质,因为a*(a^(p-2))≡1(mod p)且a*x≡1(mod p),则x=a^(p-2)(mod p)

再用快速幂可快速求之

这个用快速幂求一下,复杂度O(logn)

 
LL pow_mod(LL a, LL b, LL p){//a的b次方求余p 
    LL ret = 1;
    while(b){
        if(b & 1) ret = (ret * a) % p;
        a = (a * a) % p;
        b >>= 1;
    }
    return ret;
}
LL Fermat(LL a, LL p){//费马求a关于b的逆元 
        return pow_mod(a, p-2, p);
}

    2.扩展欧几里得(p可以不是质数)

    我们都知道模就是余数,比如12%5=12-5*2=2,18%4=18-4*4=2。(/是程序运算中的除)

    那么ax≡1 (mod p)即ax-yp=1.把y写成+的形式就是ax+py=1,为方便理解下面我们把p写成b就是ax+by=1。

就表示x是a的模b乘法逆元,y是b的模a乘法逆元。然后就可以用扩展欧几里得求了。

#include
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));
    }
}


 

 


 

你可能感兴趣的:(逆元)