求逆元的几种方法

一个讲的比较好的博客:https://blog.csdn.net/qq_27151549/article/details/81390751


  • 扩展欧几里得求逆元

这种方法常数最小

typedef  long long ll;
void extgcd(ll a,ll b,ll& d,ll& x,ll& y){
    if(!b){ d=a; x=1; y=0;}
    else{ extgcd(b,a%b,d,y,x); y-=x*(a/b); }
}
ll inverse(ll a,ll n){
    ll d,x,y;
    extgcd(a,n,d,x,y);
    return d==1?(x+n)%n:-1;
}

  • 费马小定理求逆元(%m为素数)

如果一个数m为素数,那么a^(m-1)≡1 (mod m),那么a的逆元就是a^(m-2),这是根据费马小定理推出来的。

typedef  long long ll;
ll pow_mod(ll x, ll n, ll mod){
    ll res=1;
    while(n>0){
        if(n&1)res=res*x%mod;
        x=x*x%mod;
        n>>=1;
    }
    return res;
}
ll ans = pow_mod(a,m-2,m);

 


  • 欧拉函数求逆元(%p不为素数):

      

long long eular(long long n)
{
    long long ans = n;
    for(int i = 2; i*i <= n; i++)
    {
        if(n % i == 0)
        {
            ans -= ans/i; //等价于通项,把n乘进去
            while(n % i == 0) //确保下一个i是n的素因数
                n /= i;
        }
    }
    if(n > 1)ans -= ans/n; //最后可能还剩下一个素因数没有除
    return ans;
}

注意,求出φ(n)以后依旧是mod n

然后根据a^(φ(n))≡1 (mod n),再拉个快速幂就行了。


  • 逆元打表

typedef  long long ll;
const int N = 1e5 + 5;
int inv[N];
 
void inverse(int n, int p) {
    inv[1] = 1;
    for (int i=2; i<=n; ++i) {
        inv[i] = (ll) (p - p / i) * inv[p%i] % p;
    }
}

 

你可能感兴趣的:(数论)