乘法逆元

1、什么是逆元

 

当求解公式:(a/b)%m 时,因b可能会过大,会出现爆精度的情况,所以需变除法为乘法:

设c是b的逆元,则有b*c≡1(mod m);

则(a/b)%m = (a/b)*1%m = (a/b)*b*c%m = a*c(mod m);

即a/b的模等于a*b的逆元的模;

 

 

 

2、求逆元的几种方法

 

(1).费马小定理

在p是素数的情况下,对任意整数x都有x^p≡x(mod)p。 
如果x无法被p整除,则有x^(p−1)≡1(modp) 。 
可以在p为素数的情况下求出一个数的逆元,x∗x^(p−2)≡1(modp) ,x^(p−2)即为逆元。

程序代码:

 

const int mod = 1000000009;  
long long quickpow(long long a, long long b) {  
    if (b < 0) return 0;  
    long long ret = 1;  
    a %= mod;  
    while(b) {  
        if (b & 1) ret = (ret * a) % mod;  
        b >>= 1;  
        a = (a * a) % mod;  
    }  
    return ret;  
}  
long long inv(long long a) {  
    return quickpow(a, mod - 2);  
}  

 


 

 

(2).扩展欧几里得算法求逆元

 

扩展欧几里得算法可以参考小白书;

百度百科-乘法逆元中有这样一个例子:

 

例如:4关于1模7的乘法逆元为多少?
4X≡1 mod 7
这个方程等价于求一个X和K,满足
4X=7K+1
其中X和K都是整数。

求x,k就是扩展欧几里得算法了吧~

可扩展欧几里得求逆元ax≡1(mod n)其中a,n互质;

复杂度:O(logn);

 

 

ll extend_gcd(ll a, ll b, ll &x, ll &y)
{
    if (b == 0)
    {
        x = 1, y = 0;
        return a;
    }
    else
    {
        ll r = extend_gcd(b, a % b, y, x);
        y -= x * (a / b);
        return r;
    }
}
ll inv(ll a, ll n)
{
    ll x, y;
    extend_gcd(a, n, x, y);
    x = (x % n + n) % n;
    return x;
}

 

 

(3).递推法求逆元

 

证明:

设x = p % a,y = p / a
于是有 x + y * a = p
(x + y * a) % p = 0
移项得 x % p = (-y) * a % p
x * inv(a) % p = (-y) % p
inv(a) = (p – y) * inv(x) % p
于是 inv(a) = (p – p / a) * inv(p % a) % p

然后一直递归到1为止,因为1的逆元就是1

 

代码:

 

const int mod = 1000000009;
ll inv(ll a)   
{  
    return a == 1 ? 1 : (mod - mod / a) * inv(mod % a, mod) % mod;  
}

 

posted @ 2018-03-15 22:16  GHzz  阅读(341)  评论(0编辑  收藏  举报