模逆元

模逆元的定义如下:

给定一个正整数 \(a\) 和一个正模数 \(p\) ,如果存在一个正整数 \(b\) 满足:

\[a \cdot b \equiv 1 \ (\text{mod} \ p), 1 \leq b \le p\]

则称 \(b\) 为 \(a\) 关于模数 \(p\) 的模逆元,记作 \(a^{-1} \ (\text{mod} \ p)\) 。

计算方法

单个数的模逆元

对于模逆元的计算,其本质是在求解 \(ax + py = 1\) 这个不定方程的正整数解 \(x\)。

由裴蜀定理可知,只有当 \(\gcd(a, p) = 1\) 时,方程才有整数解。

所以我们可以使用扩展欧几里得算法来计算模逆元。

这里给出计算代码:

// return the inverse of a modulo mod
template <typename T>
static T inverse_of(T a, T mod) {
    T x, y;
    (void)ex_gcd(a, mod, x, y);
    return (x % mod + mod) % mod;
}

特别地,当 \(p\) 是质数时,由费马小定理可知:

\[a^{p-1} \equiv 1 \ (\text{mod} \ p)\]

因此,\(a^{p-2} \ (\text{mod} \ p)\) 即为 \(a\) 关于模数 \(p\) 的模逆元。

多个数的模逆元

逆元存在一个重要的性质:对于 \(a\) 和 \(b\),有

\[(a \cdot b)^{-1} \equiv a^{-1} \cdot b^{-1} (\text{mod} \ p)\]

有了这个性质,我们可以通过预处理前缀积来计算多个数的模逆元。

具体地,我们用 \(prod_i\) 表示 \([1, i)\) 的前缀积取模后的结果,即:

\[prod_i = a_{i-1} \cdot prod_{i-1} \ (\text{mod} \ p)\]

那么就有 \(a^{-1}_i \equiv prod^{-1}_{i+1} \cdot prod_i \ (\text{mod} \ p)\)。

我们只需要计算出 \(prod_n\) 的模逆元,然后从后往前依次计算出每个数的模逆元即可。

这里给出代码:

// return the inverse of each element in a modulo mod
template <typename T>
static std::vector<T> inverse(const std::vector<T> &a, T mod) {
    std::vector<T> prod(a.size() + 1, 1);
    for (int i = 0; i < a.size(); i++) { prod[i + 1] = prod[i] * (a[i] % mod) % mod; }
    std::vector<T> inv(a.size());
    auto s = inverse_of(prod.back(), mod);
    for (int i = a.size() - 1; i >= 0; i--) {
        inv[i] = s * prod[i] % mod;
        s = s * a[i] % mod;
    }
    return inv;
}



    Enjoy Reading This Article?

    Here are some more articles you might like to read next:

  • 中国剩余定理及其扩展
  • 扩展欧几里德算法
  • Miller Rabin 素数测试
  • Cradle to Grave Devotion: Objective C Notes
  • gcs-front-end Development