zoukankan      html  css  js  c++  java
  • 【数论】乘法逆元

    【数论】乘法逆元

    Definition

    对于一个数 (x) 和一个模数 (p),若存在一个数字 (y),满足

    [x imes y equiv 1 pmod p ]

    则称 (y)(x) 在模 (p) 意义下的逆元,记做 (x^{-1}~equiv y pmod p)

    一个数字逆元在模意义下的运算中可以完全取代该数字的倒数。例如 (frac{x}{y}~equiv x imes y^{-1} pmod p),其中 (y^{-1}) 代表 (y) 的逆元。

    Algorithm

    Lemma

    首先需要指出的是,一个数 (x) 在模 (p) 意义下存在逆元,当且仅当 (x)(p) 互质。

    Proof

    这里只证明当 (x)(p) 不互质时不存在逆元。对于逆元的存在性,由于下面的部分给出了逆元的构造算法,这就已经证明了在互质时逆元是存在的。

    反证法,设对于任意的 (x in Z^+),存在 (x^{-1} in Z^+)

    [x imes x^{-1} equiv 1 pmod p~~~~~~(1) ]

    [gcd(x,~p) = d eq 1~~~~~~(2) ]

    根据同余的定义,((1)) 可以写成:

    [x imes x^{-1} = k imes p + 1~~~~~~(3) ]

    其中 (k) 是一个非负整数。

    ((3)) 的等号两侧同时除以 ((2)) 中的 (d)

    [frac{x imes x^{-1}}{d}~=~frac{k imes p + 1}{d}~~~~~~(4) ]

    整理得到

    [frac{x}{d} imes x^{-1}~=~frac{p}{d} imes k + frac{1}{d}~~~~~~(5) ]

    因为 (d = gcd(x, p)),所以 (d) 一定是 (x)(p) 的因数。所以

    (frac{x}{d})(frac{p}{d}) 都是整数,进而 (frac{p}{d} imes k) 是整数,(frac{x}{d} imes x^{-1}) 是整数。

    而因为 (d eq 1),所以 (frac{1}{d}) 一定不是整数,因此 (frac{p}{d} imes k + frac{1}{d}) 不是整数。

    于是等号左侧是整数,等号右侧不是整数,左侧一定不等于右侧,产生矛盾。这就矛盾证明了 (x) 在模 (p) 意义下存在逆元仅当 (x)(p) 互质。


    以下介绍求逆元的算法:

    求单个数字的逆元

    Algorithm 1

    [x imes x^{-1}~equiv 1 pmod p ]

    显然可以转化成方程

    (x imes x^-1 = 1 + kp)

    (y = -k),移项得到

    [x imes x^{-1} + y imes p = 1 ]

    注意到这个式子就是扩展欧几里得算法所求的式子

    [ax + by = 1 ]

    只不过 (x) 作为一个常数,是欧式式子里的 (a),同理 (p) 是欧式式子里的 (b)。使用扩展欧几里得算法求解上面这个式子即可。时间复杂度 (O(log x))

    Algorithm 2

    根据欧拉定理

    (x^{phi(p)} equiv 1 pmod p)

    其中 (phi) 为欧拉函数,(phi(p)) 表示小于 (p) 的正整数中与 (p) 互质的数的个数。

    等式两侧同乘 (x^{-1}) 可以得到

    [x^{phi(p) - 1} equiv x^{-1} pmod p ]

    显然当 (p) 是一个质数时,(phi(p) = p - 1),这时可以 (O(1)) 算出 (phi(p) - 1) 的值,即可用快速幂 (O(log x)) 求出 (x) 的逆元。这个算法好写好记,常数也较小。一般当 (p)int 范围内的质数时选择此算法。当 (p) 不在 int 范围内时,由于快速幂时需要两个 long long 相乘,会爆精度。

    有关欧拉定理的证明可以看这里

    (n) 以内所有正整数模 (p) 的逆元

    显然,由于 (n) 以内所有正整数都有在模 (p) 意义下的逆元,所以 (p)(n) 以内的所有数互质。

    结论:设 (inv_i)(i) 的逆元,则有递推式

    [inv_i equiv leftlfloorfrac{p}{i} ight floor imes inv_{p mod i} pmod p ]

    边界条件为

    [inv_1 = 1 ]

    Proof

    首先 (inv_1 = 1) 显然成立。

    对于 (i > 1),写出 (p) 除以 (i) 的带余除法表达式:

    [p = ki + r ]

    其中 (r in [0, i - 1])

    等式两侧对 (p) 取余数,有

    [0 equiv ki + r pmod p ]

    移项得到

    [r equiv -ki pmod p ]

    两侧同乘 (i^{-1} imes r^{-1}),整理得到

    [i^{-1} equiv -kr^{-1} pmod p ]

    由于 (k = leftlfloorfrac{p}{i} ight floor)(r = p mod i),所以原式得证。

    又因为 (r < i),所以在计算 (inv_i) 时,(inv_r) 已经被计算完成,所以上述递推可以完成。

    证毕。

    这样做的时间复杂度显然是 (O(n))

    (n!) 的逆元

    因为 ((n!)^{-1} equiv frac{1}{n!} equiv prod_{i = 1}^n n^{-1}),所以线性筛出 (n) 以内所有数字的逆元时,可以顺便求出 (n!) 的逆元。时间复杂度 (O(n))

    Code

    Ex_Gcd

    #include <iostream>
    
    typedef long long int ll;
    
    ll x, p;
    
    void Ex_gcd(const ll a, const ll b, ll &X, ll &Y);
    
    int main() {
      std::cin >> x >> p;
      ll a, b;
      Ex_gcd(x, p, a, b);
      std::cout << (a % p + p) % p << std::endl;
      return 0;
    }
    
    void Ex_gcd(const ll a, const ll b, ll &X, ll &Y) {
      if (b == 0) {
        X = 1; Y = 0;
      } else {
        Ex_gcd(b, a % b, Y, X);
        Y -= a / b * X;
      }
    }
    

    欧拉定理

    #include <iostream>
    
    typedef long long int ll;
    
    ll X, p;
    
    ll mpow(ll x, ll y);
    
    int main() {
      std::cin >> X >> p;
      std::cout << mpow(X, p - 2) << std::endl;
      return 0;
    }
    
    ll mpow(ll x, ll y) {
      ll _ret = 1;
      while (y) {
        if (y & 1) (_ret *= x) %= p;
        y >>= 1;
        (x *= x) %= p;
      }
      return _ret;
    }
    

    线性求逆元

    这里的 factinv 即为阶乘逆元。

    #include <cstdio>
    
    const int maxn = 3000005;
    
    int n, p;
    int inv[maxn], factinv[maxn];
    
    int main() {
      scanf("%d%d", &n, &p);
      factinv[1] = inv[1] = 1;
      printf("%d
    ", 1);
      for (int i = 2; i <= n; ++i) {
        inv[i] = 1ll * (p - p / i) * inv[p % i] % p;
        printf("%d
    ", inv[i]);
        factinv[i] = 1ll * factinv[i - 1] * inv[i] % p;
      }
      return 0;
    }
    
  • 相关阅读:
    转Oracle、MySql、SQLServer 数据分页查询
    转 DevExpress-ASPxPageControl 动态添加 TabPage 内容
    淘淘实惠多www.taohuiduo.com-专注独家折扣、1折特卖、9块9包邮、全场包邮
    "命名空间"system.web"中不存在类型或命名空间名称security"错误解决方法
    转摘 Eclipse智能提示及快捷键
    转(C#)Winform中MD5加密
    ComboBoxEdit数据绑定
    格式化日期和时间
    时间格式转换
    如何安装ESXi的补丁
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/12158367.html
Copyright © 2011-2022 走看看