【初等数论】乘法逆元略解

乘法逆元

\(1、\)定义:\(\frac{1}{a} \equiv b\pmod{p}\),则称\(b\)\(a\)在模\(p\)意义下的乘法逆元,记为\(inv(a)\)\(a^{-1}\)

\(2、\)在模\(p\)意义下讨论乘法逆元的存在性

​  设\(a^{-1} = x\)

​  \(a\cdot x \equiv 1\)

​  \(\Leftrightarrow a \cdot x = 1 - py\)

​  \(\Leftrightarrow a x+py = 1\)

​  裴蜀定理告诉我们,该方程当且仅当\(gcd(a,p) = 1\)时有解。也就是说,当且仅当\(a\)与模数\(p\)互质时存在\(a\)的乘法逆元。因此大部分有理数取模问题给定的模数都是质数,这样能够在\(a\bmod p \neq 0\)的情况下保证存在\(a\)的逆元。

\(3、\)乘法逆元的四种推导方式

  1. 扩展欧几里得算法

    \(a\)的逆元,也就是求出\(\Leftrightarrow a x+py = 1\)的一组解,使用扩展欧几里得算法直接求解得\(x\)即可。

    void exgcd(int& x, int& y, int a, int b) {
      if (!p) {
        x = 1, y = 0;
        return;
      }
      exgcd(y, x, b, a % b);
      y -= a / b * x;
    }
    
  2. 费马小定理/扩展欧拉定理

    费马小定理:对于质数\(p\)\(a^{p} \equiv a \pmod{p}\)

    \(a^{p-1} \equiv 1\pmod {p}\)

    也就是说,\(a^{p-2}\)即为\(a \bmod p\)意义下的逆元,使用快速幂求解。

    费马小定理是欧拉定理在\(p\)为质数时的特殊情况,实现起来没有区别。这里不深入展开叙述欧拉定理。

    LL fpow(LL a, LL p) {
      LL b = p - 2, ret = 1;
      for (; b; b >>= 1) {
        if (b & 1) ret = ret * a % p;
        a = a * a % p;
      }
      return ret;
    }
    
  3. 线性递推\(1\sim n\)的逆元

    显然有\(1^{-1} = 1\).

    \(r = p \bmod i, k = \lfloor \frac{p}{i} \rfloor\)

    \(\Rightarrow ki + r \equiv 0 \pmod p\)

    两边同乘\(i^{-1}r^{-1}\),得

    \(kr^{-1} + i^{-1} \equiv 0 \pmod p\)

    \(\Leftrightarrow i^{-1} = -\lfloor \frac{p}{i} \rfloor \cdot (p \bmod i)^{-1} \pmod p\)

    得到如上递推式,解毕。

    void get_inv(int n, int p) {
      inv[1] = 1;
      for (int i = 2; i <= n; ++i)
        f[i] = (LL)(p - p / i) * inv[p%i] % p;//p - p / i:去掉负数
    }
    
  4. 线性递推\(a_1 \sim a_n\)的逆元\((a_i \in N_+)\)

    以下表达式均在\(\bmod p\) 意义下。

    \(f_i = \prod_{j = 1}^{i}a_j\)

    首先可以线性递推求出\(f_{1 \sim n}\)

    我们发现,对\((f_i)^{-1}\)可推导出如下递推式:

    $ f_i \times (f_{i})^{-1} \equiv 1$

    \(\Rightarrow a_i \cdot f_{i-1} \cdot (f_i)^{-1} \equiv 1\)

    \((f_i)^{-1} \equiv (f_{i+1})^{-1} \times a_{i+1}\)

    那么我们可以结合费马小定理/扩展欧几里得算法

    求出\((f_n)^{-1}\),然后倒着线性迭代求出\((f_{1 \sim n-1})^{-1}\)

    现在我们求出了原数列前缀积数列的逆元,考虑着手由\(\{f\}^{-1}\)数组推导出\(\{a\}^{-1}\)

    \(a_i \times a_i^{-1} \equiv 1\)

    \(\Leftrightarrow \frac{f_i}{f_{i-1}} \cdot a_i^{-1} \equiv 1\)

    \(\Leftrightarrow a_i^{-1} \equiv \frac{f_{i-1}}{f_i}\)

    \(a_i^{-1} \equiv f_{i-1} \cdot (f_i)^{-1}\)

    得到如上递推式,解毕。

    因此,最后我们再使用费马小定理求出\(a_1^{-1}\),就可以递推一遍求出原数列各项的逆元了。

    int a[maxn], inv[maxn], V[maxn], f[maxn], n, k, p;
    LL ans;
    int fpow(LL a, LL b) {
    	LL ret = 1;
    	while (b) {
    		if (b & 1) ret = ret * a % p;
    		b >>= 1;
    		a = a * a % p;
    	}
    	return ret;
    }
    void get_inv() {
    	f[0] = 1;
    	for (int i = 1; i <= n; ++i) {
    		read(a[i]);
    		f[i] = (LL)a[i] * f[i-1] % p;
    	}
    	V[n] = fpow(f[n], p - 2);
    	for (int i = n - 1; i; --i) V[i] = (LL)V[i+1] * (a[i+1]) % p;
    	for (int i = n; i > 1; --i) inv[i] = (LL)f[i-1] * V[i] % p;
    	inv[1] = fpow(a[1], p - 2);
    }
    
posted @ 2019-10-30 10:54  onyYuan  阅读(311)  评论(0编辑  收藏  举报