乘法逆元_三种方法

//方法一:  扩展欧几里得 (求逆元 调用mod_reverse函数)
// 限定条件 a n 互质  log(n)
// @a 数
// @n 模数
inline long long mod_reverse(long long a,long long n)
{
    long long x,y,d=extend_gcd(a,n,x,y);
    if(d==1) {
        if(x%n<=0)return x%n+n;  // 答案是负的要置为正的.
        else return x%n;
    } else return -1ll;
}

// 限定条件 a b 互质
// @a 是 这个数  
// @b 是 模数 
// @x 是 返回的逆元 返回-1 表示没有逆元
// @y 暂时不知道是什么...
long long extend_gcd(long long a,long long b,long long &x,long long &y)
{
    if(a==0&&b==0)
        return -1ll;
    if(b==0)
    {
        x=1ll;
        y=0ll;
        return a;
    }
    long long d=extend_gcd(b,a%b,y,x);
    y-=a/b*x;
    return d;
}

//方法二:  费马小定理
// 模数是一个质数 复杂度 log(n)
// 原理, 当p是一个质数时,有 inv(a) = a^(p-2) % p;
long long pwr4(long long a, long long k, long long jmod) {
    long long res = 1, base = a;
    while (k) {
        if (k&1)  res = res * base % jmod;
        base = base * base % jmod;
        k >>= 1;
    }
    return res;
}

long long mod_reverse(long long a, long long n) 
{
    return pwr4(a, n-2, n);
}

//方法三:  欧拉定理
// 模数不是质数的情况
// 由a^φ(p)≡ 1(mod p) 得 a^(φ(p)−1)是a的逆元 
// φ(p)是欧拉函数
// O(n)的时间可以递推出1~n在 mod p 意义下的逆元
// 没用过 所以先给出别人的代码  kuangbin大神板子也有代码.
void inv3(LL mod)//线性递推求逆元 
{
    inv[1]=1;
    for(int i=2;i<=mod-1;i++)
    {
        inv[i]=(mod-mod/i)*inv[mod%i]%mod;
        cout<<inv[i]<<" ";
    }
}

 

posted @ 2018-08-05 13:13  过路人1998  阅读(175)  评论(0编辑  收藏  举报