乘法逆元

首先附上学习的博客  https://blog.csdn.net/sdfzchy/article/details/76098066 
https://blog.csdn.net/STcyclone/article/details/52081822
相关 百科乘法逆元 https://baike.baidu.com/item/%E4%B9%98%E6%B3%95%E9%80%86%E5%85%83/5831857?fr=aladdin
逆元 https://baike.baidu.com/item/%E9%80%86%E5%85%83%E7%B4%A0?fromtitle=%E9%80%86%E5%85%83&fromid=11054145
同余方程 https://baike.baidu.com/item/%E5%90%8C%E4%BD%99%E6%96%B9%E7%A8%8B/9823007



乘法逆元 至于我们为什么要讨论模意义下的运算呢
? 例如 1. 很多算法题的数值运算可能会溢出,为了研究和讨论算法,我们引入了模的概念 2. 哈希的时候,数值溢出是很正常的,所以我们需要通过取模,把哈希函数的数值限定在我们可控的范围内,让我们可以继续通过哈希的规则进行存放. 为什么需要乘法逆元 模意义下的加减乘运算都是具有封闭性的,但除法确是例外, 所以我们就要找一种在模意义下代替除法运算的东西. 即是说, 我们在模意义下的除法同一通过乘该数的乘法逆元来等价替代. 什么是乘法逆元呢? 定义: 在a,p互为质数的条件下, 如果 a * b 余 p 等于1 即 a * b % p == 1 则 我们称 b 是 mod p意义下a的逆元. 记作 b = inv(a) // 注, a * b 余 p 等于1 的通常写法时 a * b 同余 p == 1 例如: a / b % p 因为 模意义下是没有除法的. 但是我们可以转换成乘法做等价替换. 当a 与 p 互质时, a / b % p <==> a * inv(a) % p 同时 这也是我们通常取质数作为模数的原因(同时质数还有费马小定理,可以较快速的求出逆元.) // 另注: 其他: 关于同余方程 同余方程是一个数学方程式。 该方程式的内容为:对于一组整数Z, Z里的每一个数都除以同一个数m, 得到的余数可以为0,12,...m-1,共m种。 我们就以余数的大小作为标准将Z分为m类。每一类都有相同的余数。 那么 如果求解一个数的逆元呢. // 记得这个数和模数必须互质哟

 

 

方法一:  扩展欧几里得 (求逆元 调用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:05  过路人1998  阅读(190)  评论(0编辑  收藏  举报