码迷,mamicode.com
首页 > 其他好文 > 详细

深入浅出乘法逆元

时间:2018-03-01 17:08:03      阅读:164      评论:0      收藏:0      [点我收藏+]

标签:head   otn   必须   关于   mes   html   code   href   通过   

深入浅出乘法逆元
 1.模的运算律
 2.定义
 3.求解
  3.1费马小定理
  3.2扩展欧几里得算法
  3.3线性求解

深入浅出乘法逆元

模的运算律

先来一波模运算律表:

运算律 内容
交换律 \((a+b)\%p=(b+a)\%p\)
\((a\times b)\%p=(b\times a)\%p\)
结合律 \(((a+b)\%p+c)\%p=(a+(b+c)\%p)\%p\)
\(((a\times b)\%p\times c)\%p=(a\times (b\times c)\%p)\%p\)
分配率 \(((a+b)\%p\times c)\%p=((a\times c)\%p+(b\times c)\%p)\%p\)
\((a\times b)\%p=(a\%p\times b\%p)\%p\)
\((a+b)\%p=(a\%p+b\%p)\%p\)
\((a-b)\%p=(a\%p-b\%p)\%p\)

定义

有的时候我们需要对一个数取模,这很简单。但是在取模的过程中出现了除数,那么取模就没这么简单了:
\[\frac{7}{2}\%4=3\%4=3\]注意:\(\frac{7\%4}{2}=\frac{3}{2}=1\)错误的
但万一是\(\frac{7^{10000}}{2}\%4\)计算机可无法先计算\(\frac{7^{10000}}{2}\)\(\pmod4\),因为数字太大了。
这个时候我们就需要用到乘法逆元了,事实上:\(\frac{7^{10000}}{2}=(7*3)^{10000}\)。我们运用模的运算律可以通过边乘边取模即可得到答案,其中3是7在\(\pmod 4\)意义下的逆元。
关于逆元的严格定义如下:

\(若整数b,m互质,并且b\mid a,则存在整数x,使得a/b\equiv a*x\pmod m,则称x为b的模m乘法逆元,记为b^{-1}\pmod m\)

求解

3.1费马小定理

1
因为\(a/b\equiv a*b^{-1}\equiv a/b*b*b^{-1}\pmod m\),所以\(b*b^{-1}\equiv 1\pmod m\)2
如果m是质数(此时我们用符号\(p\)代替\(m\))并且\(b<p\),根据费马小定理\(b^{p-1}\equiv 1\pmod p\),即\(b*b^{p-2}\equiv1\pmod p\)。因此,当模数\(p\)为质数时,\(b^{p-2}\)\(b\)的乘法逆元。
到最后我们可以用快速幂来迅速求出\(b^{p-2}\)。代码如下:

int ksm(int a,int b,int p) {
    int ans=1;
    for(; b; b>>=1,a=a*a%p)if(b&1)ans=ans*a%p;
    return ans;
}

时间复杂度是\(O(\log n)\)

3.2扩展欧几里得算法

扩展欧几里得算法的具体内容参考我写的:浅析扩展欧几里得算法(exgcd)
根据逆元的定义我们要求的是\(a*x\equiv1\pmod m\)关于x的同余方程,其中x为a在\(\pmod m\)意义下的逆元
事实上\[ax=by+1······①\]也就是\(ax\div m=y······1\)
变形①式得:\[ax-by=1\]
既然\(a,b\)都已知,就不难求出\(x和y\)了(但要注意\(y\)的系数\(-b\)必须是正整数,因为在计算机计算过程中如果模数是负的将导致结果出错)如果\(-b\)不是正整数,我们同时改变\(a,b\)的符号即可,\(a\)的符号并不影响结果。扩展欧几里得算法代码如下:

int exgcd(int a,int b,int &x,int &y) {
    if(b) {
        int c=exgcd(a,b,y,x);
        y-=a/b*x;
        return c;
    } else {
        x=1;
        y=0;
        return a;
    }
}

时间复杂度是\(O(\ln n)\)

3.3线性求解

当我们需要求解大量的逆元的时候,前两种的方法时间复杂度都要乘以\(n\),时间复杂度都不是很理想。所以我们就用\(O(n)\)的时间来快速求解。具体做法如下:假设我们要求x的逆元,那么:\[m=k*x+r\]\[k*x+r\equiv0\pmod m\]同乘以\(x^{-1}*r^{-1}\)得:\[k*r^{-1}+x^{-1}\equiv0\pmod m······①\]将②式变形得:\[x^{-1}\equiv-k*r^{-1}\pmod m\]
所以我们得到:\[x^{-1}=-\lfloor m/x\rfloor*(m\%x)^{-1}\]
那么只要建一个数组inv,初始值inv[1]=1。所以代码如下:

    for(int i=2; i<=n; i++)
        inv[i]=-(p/i)*inv[p%i];

  1. 这种方法的常数比较大。?

  2. \(b^{-1}\equiv b^{-1}\pmod m\)其中前一个是\(\div b\),后一个是\(a\)的逆元\(b\);根据模的运算律\((a/b*b*b^{-1})\%m=((a/b)\%m*((b*b^{-1})\%m)\%m\),显然\((b*b^{-1})\%m=1\)?

深入浅出乘法逆元

标签:head   otn   必须   关于   mes   html   code   href   通过   

原文地址:https://www.cnblogs.com/kcfzyhq/p/8488243.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!