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

乘法逆元

时间:2018-01-23 23:16:25      阅读:213      评论:0      收藏:0      [点我收藏+]

标签:pre   tps   int   www.   lock   span   十分   power   a*   

乘法逆元

逆元,一般用于求\(\frac{a}{b} (\bmod {p})\)
这种东西,我看到都是十分懵的,原来一直不打算去学习,可现实十分残酷,
导致很多次考试都很被动,我下定决心学一学2333。

逆元定义

\(a*x\equiv1 (\bmod {b})\),且\(a\)\(b\)互质,那么我们就能定义:
\(x\)\(a\)的逆元,记为\(a^{-1}\),所以我们也可以称\(x\)\(a\)的倒数,
上列计算都在$\bmod b $意义下。

所以对于\(\frac{a}{b} (\bmod {p})\),我们就可以求出\(b\)\(\bmod {p}\)
下的逆元,然后乘上\(a\),再\(\bmod {p}\),就是这个乘法逆元的值了。

算逆元的方法

  • 拓展欧几里得

这个方法十分容易理解,而且对于单个查找效率似乎也还不错,比后面要介绍的
快速幂的方法大部分要快(尤其对于\(\bmod {p}\)比较大的时候)。
这个就是利用拓欧求解 线性同余方程\(a*x \equiv c (\bmod {b})\)
\(c=1\)的情况。我们就可以转化为\(a*x + b*y = 1 (\bmod {b})\)
求解这个方程的解。

代码比较简单:

void exgcd (ll a, ll b, ll &x, ll &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return ;
    }
    exgcd (b, a % b, x, y);
    ll tmp = x;
    x = y;
    y = tmp - a / b * y;    
}
        ll x, y;
    exgcd (i, p, x, y);
    x = (x % p + p) % p;
    printf ("%d\n", x);
  • 快速幂

这个做法要利用 费马小定理

\(p\)为素数,\(a\)为正整数,且\(a\)\(p\)互质。
则有\(a^{p-1} \equiv 1 (\bmod {p})\)

这个我们就可以发现它这个式子右边刚好为1。

所以我们就可以放入原式,就可以得到:

\(a*x\equiv 1 (\bmod {b})\)

\(a*x\equiv a^{p-1} (\bmod {b})\)

\(x \equiv a^{p-2} (\bmod {b})\)

所以我们可以用快速幂来算出 \(a^{p-2} (\bmod {b})\)的值,这个数就是它的逆元了

代码也很简单:

ll fpm(ll x, ll power, ll mod) {
    x %= mod;
    ll ans = 1;
    while (power) {
        if (power & 1) ans = (ans * x) % mod;
        x = (x * x) % mod;
        power >>= 1;
    }
    return ans;
}
printf ("%lld\n", fpm(i, p-2, p) );
  • 线性算法

用于求一连串数字对于一个\(\bmod p\)的逆元。洛谷P3811
只能用这种方法,别的算法都比这些要求一串要慢。

首先我们有一个,\(1^{-1}\equiv 1(\bmod p)\)
然后设\(p=k*i+r,r<i,1<i<p\),再将这个式子放到\(\bmod {p}\)意义下就会得到:
\(k*i+r \equiv 0 (\bmod p)\)

然后乘上\(i^{-1}\),\(r^{-1}\)就可以得到:
\(k*r^{-1}+i^{-1}\equiv 0 (\bmod p)\)

\(i^{-1}\equiv -k*r^{-1} (\bmod p)\)

\(i^{-1}\equiv -\lfloor \frac{p}{i} \rfloor*(p \bmod i)^{-1} (\bmod p)\)

于是,我们就可以从前面推出当前的逆元了。代码也就两行:

    a[i] = - (p / i) * a[p % i];
a[i] = (a[i] % p + p) % p;

阶乘逆元\(O(n)\)

证明:
\(inv[i+1]=\frac{1}{(i+1)!}\)

\(inv[i+1]*(i+1)=\frac{1}{i!}=inv[i]\)

所以我们可以求出\(n!\)的逆元,然后逆推,就可以求出\(1...n!\)所有的逆元了。

递推式为

inv[i+1]*(i+1)=inv[i]

乘法逆元

标签:pre   tps   int   www.   lock   span   十分   power   a*   

原文地址:https://www.cnblogs.com/zjp-shadow/p/8338011.html

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