求逆元基本方法

乘法逆元小结

乘法逆元,一般用于求

$\frac{a}{b}$

$\pmod{p}$

的值($p$ 通常为质数),是解决模意义下分数数值的必要手段。

有兴趣可以点进我的博客看看啊qwq

逆元定义

$\frac{aas}{asb}$

若a*x\equiv1 \pmod {b}a∗x≡1(modb),且aa与bb互质,那么我们就能定义: xx 为 aa 的逆元,记为a^{-1}a−1,所以我们也可以称 xx 为 aa 在 \bmod bmodb意义下的倒数,

所以对于 \displaystyle\frac{a}{b} \pmod {p}ba​(modp) ,我们就可以求出 bb 在 \bmod {p}modp 下的逆元,然后乘上 aa ,再 \bmod {p}modp,就是这个分数的值了。

求解逆元的方式

拓展欧几里得

这个方法十分容易理解,而且对于单个查找效率似乎也还不错,比后面要介绍的大部分方法都要快(尤其对于 \bmod {p}modp 比较大的时候)。

这个就是利用拓欧求解 线性同余方程 $a*x\equiv c\pmod{b}$ 的c=1c=1的情况。我们就可以转化为解 a*x + b*y = 1a∗x+b∗y=1 这个方程。

求解这个方程的解。不会拓欧可以点这里~

而且这个做法还有个好处在于,当 a \bot pa⊥p (互质),但 pp 不是质数的时候也可以使用。

代码比较简单:

void Exgcd(ll a, ll b, ll &x, ll &y) {

    if (!b) x = 1, y = 0;

    else Exgcd(b, a % b, y, x), y -= a / b * x;

}

int main() {

    ll x, y;

    Exgcd (a, p, x, y);

    x = (x % p + p) % p;

    printf ("%d\n", x); //x是a在mod p下的逆元

}

快速幂

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

若pp为素数,aa为正整数,且aa、pp互质。 则有a^{p-1} \equiv 1 (\bmod {p})ap−1≡1(modp)。

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

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

a*x\equiv 1 \pmod pa∗x≡1(modp)

a*x\equiv a^{p-1} \pmod pa∗x≡ap−1(modp)

x \equiv a^{p-2} \pmod px≡ap−2(modp)

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

代码也很简单:

ll fpm(ll x, ll power, ll mod) {

    x %= mod;

    ll ans = 1;

    for (; power; power >>= 1, (x *= x) %= mod)

        if(power & 1) (ans *= x) %= mod;

    return ans;

}

int main() {

    ll x = fpm(a, p - 2, p); //x为a在mod p意义下的逆元

}

线性算法

用于求一连串数字对于一个\bmod pmodp的逆元。洛谷P3811

只能用这种方法,别的算法都比这些要求一串要慢。

首先我们有一个,1^{-1}\equiv 1 \pmod p1−1≡1(modp)

然后设 p=k*i+r,(1<r<i<p)p=k∗i+r,(1<r<i<p) 也就是 kk 是 p / ip/i 的商,rr 是余数 。

再将这个式子放到\pmod p(modp)意义下就会得到:

k*i+r \equiv 0 \pmod pk∗i+r≡0(modp)

然后乘上i^{-1}i−1,r^{-1}r−1就可以得到:

k*r^{-1}+i^{-1}\equiv 0 \pmod pk∗r−1+i−1≡0(modp)

i^{-1}\equiv -k*r^{-1} \pmod pi−1≡−k∗r−1(modp)

i^{-1}\equiv -\lfloor \frac{p}{i} \rfloor*(p \bmod i)^{-1} \pmod pi−1≡−⌊ip​⌋∗(pmodi)−1(modp)

于是,我们就可以从前面推出当前的逆元了。

代码也很短:

inv[1] = 1;

for(int i = 2; i < p; ++ i)

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

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

因为有如下一个递推关系。

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

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

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

递推式为

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

所以我们可以求出 \displaystyle \forall i, i!,\frac{1}{i!}∀i,i!,i!1​ 的取值了。

然后这个也可以导出 \displaystyle \frac{1}{i} \pmod pi1​(modp) 的取值,也就是

\displaystyle \frac{1}{i!} \times (i - 1)! = \frac{1}{i} \pmod pi!1​×(i−1)!=i1​(modp)

具体实现可以参考我这发提交(卡了常。。)

 

猜你喜欢

转载自www.cnblogs.com/guoshaoyang/p/10940335.html