• 乘法逆元


    求解逆元有如下几种方式:

    1. 如果 mod 为 素数,那么可以使用费马小定理+快速幂求解

    2. 如果 gcd(a,mod)==1 其中,a为求逆元素,并且满足前面的等式保证a存在逆元。 那么可以使用 扩展欧几里得

    3. 递推法快速打表求解多个逆元, 要求 mod 必须为奇质数

    4. 如果 mod 不为素数,那么可以使用通用解法,这里不详细讲(因为我也不会

    下面讲解1,2,3方法

    方法一:(如果 mod 为 素数,那么可以使用费马小定理+快速幂求解)

    1. 费马小定理

    如果 gcd(a,p) == 1, 并且 p 为素数,那么就有 

    公式变形:

    所以:求解 a 的逆元,就是求解 。因此需要使用到快速幂

    2. 代码:求 a 在 mod 下的乘法逆元

     1 //求 m^n % k 
     2 ll quick_power(ll m, ll n, ll k){
     3     ll ans = 1;
     4     m %= k;
     5     while(n){
     6         if(n & 1)
     7             ans = ans * m % k;
     8         n >>= 1;
     9         m = m * m % k;
    10     }
    11     return ans;
    12 }
    13 
    14 ll inverse_quick_pow(ll a, ll mod){
    15     return quick_power(a,mod-2,mod);
    16 }

    方法二:如果 gcd(a,mod)==1 其中,a为求逆元素,并且满足前面的等式保证a存在逆元。 那么可以使用 扩展欧几里得

    1. 扩展欧几里得:传送门

    2. 由于求解逆元,其实就是解方程 ax+py ≡ 1 (mod p)

    3. 代码: 求 a 在 mod 下的乘法逆元

     1 //ax + by = gcd(a,b)
     2 //gcd 保存了 a,b 的最大公约数
     3 void ext_gcd(ll a, ll b, ll &gcd, ll &x, ll &y) {
     4     if (!b) { gcd=a; x=1; y=0; }
     5     else { ext_gcd(b,a%b,gcd,y,x); y-=(a/b)*x; }
     6     // 理解上面这个这句话就用上面的 extend_gcd 来理解,主要是使用了引用的概念
     7     // 并且 ext_gcd 在 y-=(a/b)*x 上面,也就是说 ext_gcd 参数中的 x,y 都是
     8     // 下一层函数返回的 x2, y2
     9     // 然后使用 y-=(a/b)*x 处理一下本层函数 y1 即可
    10 }
    11 
    12 
    13 ll inverse_ext_gcd(ll a, ll mod) {
    14     ll x, y, gcd;
    15     ext_gcd(a, mod, gcd, x, y);
    16     // gcd(x,mod) ==1 是有逆元的充要条件
    17     // 当满足有逆元的时候,需要调整 x 到 0-mod 之间
    18     // 对于负数 x+mod 即可调整正确,
    19     // 为了编码统一将正数页进行调整, (x+mod)%mod
    20     return gcd == 1 ? (x + mod) % mod : -1;
    21 }

     方法三:递推法快速打表求解多个逆元, 要求 mod 必须为奇质数

    1. 原理:基于一个公式  

    2. 初始条件: inv[1]=1;

    3. 代码:

     1 // 递推法快速求 逆元
     2 const int maxn = 3e3 + 5;
     3 ll inv[maxn];
     4 
     5 //要求: mod 为奇质数
     6 //公式: inv[i]=(mod - mod /i) * inv[mod%i]%mod
     7 //初始条件: inv[1]=1;
     8 void inverse_recursion(ll mod) {
     9     inv[1] = 1;
    10     for (int i = 2; i < maxn; i++)
    11         inv[i] = (mod - mod / i) * inv[mod % i] % mod;
    12 }
  • 相关阅读:
    Python数据类型知识点
    CentOS上部署Kubernetes集群
    运维面试题(持续更新)
    shell拷贝文件到另一台机器
    第十一章——线程【01】
    07 类 | 类的静态成员
    【C++ Primer | 19】控制内存分配
    002 模板实参推断、重载与模板
    16 模板与泛型编程 | 定义模板
    C++ | 类
  • 原文地址:https://www.cnblogs.com/TianyuSu/p/9391316.html
Copyright © 2020-2023  润新知