浅谈乘法逆元

乘法逆元,一般用于求解(frac{A}{C}(mod ~ P))的值,因为我们通过模的定义可以知道上式显然不等于(frac{A \% P}{B \% P})。例子有很多不再举了。那么如果我们要求上式大多数情况都需要借助逆元。

首先是定义:

若(A imes X equiv 1 (mod ~ P)),并且(A perp P)((perp):互质),那么我们就称(X)为(A)的逆元,简称为(A^{- 1}),也就是(A)在(mod ~ P)意义下的倒数。

借此我们可以知道(frac{A}{C}(mod ~ P))的求法:我们先求出(C)在(mod ~ P)意义下的逆元,然后(imes A)就是答案了。那么我们主要求的就是(C)的逆元。

扩展欧几里得版

首先从最简单开始,就是一个扩展欧几里得,直接求解(A imes X + P imes Y = 1)就行了。

inline void Exgcd(int A, int P, int X, int Y) {

if (! B) X = 1, Y = 0 ;

else Exgcd(P, A % P, Y, X), Y -= A / B * X ;

}

这个方法虽然时间上比较慢,但是有一个优点,就是当(A)与(P)不互质的时候,依然可以适用。但是下面介绍的其他方法就必须满足(A perp P)了。

费马小定理版

回顾一下费马小定理的内容:

若(A perp P), 则(A^{P - 1} equiv 1(mod ~ P))。

我们可以把它运用到乘法逆元里。结合(A imes X equiv 1(mod ~ P))可以得到(A imes X equiv A^{P - 1}(mod ~ P))。当(P)为质数的时候,我们把左右都除以一个(A)可以得到(X equiv A^{P - 2}(mod P))。然后就可以一个快速幂求出来了。

inline void Fpm(int A, int P) {

int Ans = 1 ; int M = P ;

A %= M ; P -= 2 ;

while (P) {

if (P & 1) Ans = Ans * A % M ;

A = A * A % M ; P >> = 1 ;

} return Ans % M ;

}

上面的复杂度是(O(logN))的,在求多个逆元的时候可能(O(NlogN))是过不去的。当然我们还有一种利用地推打出逆元表的方法做到(O(N)).

欧拉筛版

设(INV[i])为(i)的逆元。我们知道有(INV[A] = A ^ {P - 2}(mod ~ P),~INV[B] = B ^ {P - 2} (mod ~ P))

我们利用费马小定理可以得(INV[A imes B] = (AB) ^ {P - 2} (mod P))也就是说(INV[A imes B] = INV[A] imes INV[B])。求得递推式。我们就可以利用欧拉筛。

递推版

为了方便起见就直接写过程了。

设(P = kA + r~~(r in [0, P)~))。因为我们知道任何一个数都可以写成这个形式嘛。

那么有(kA + r equiv 0 (mod ~ P))

因为(A^{P - 1} equiv 1(mod ~ P))

所以((kA +r) imes A^{- 1} imes r^{- 1} equiv 0 (mod ~ P))

把左边的括号拆开得(kr^{- 1} + A^{- 1} equiv 0 (mod ~ P))

移项:(A^{- 1} equiv -kr^{- 1})

在这里我们知道(k = lfloor frac{P}{A} floor)。

(A^{- 1} equiv -lfloor frac{P}{A} floor imes r^{- 1})

并且我们还知道(r ≤ A)。那么我们就可以借用数组(INV[r])完成递推。同时我们还知道(r = P \% A)

最后得到(INV[A] = (P - lfloor frac{P}{A} floor) imes INV[P\% A])

递推完成,时间复杂度(O(N))。

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

INV[i] = P - (P / i) * INV[P % i] % P;

当然不要忘了初始化的问题。

乘法逆元 java_浅谈乘法逆元(示例代码)相关推荐

  1. file相对路径java_浅谈java 中文件的读取File、以及相对路径的问题

    一.对于java项目中文件的读取 1.使用system 或是 系统的properties对象 ①直接是使用 string relativelypath=system.getproperty(" ...

  2. 后端语言除了java_浅谈后端语言优缺点

    浅谈后端语言优缺点 兄弟连教育在前不久,回答了一个关于后端语言选型的问题,那么后端语言都有哪些,存在什么样的优缺点?因此兄弟连与大家分享一下心得. 语言优缺点 C/C++ C 语言虽然是非常贴近操作系 ...

  3. python列表和数组区别java_浅谈numpy中np.array()与np.asarray的区别以及.tolist

    array和asarray都可以将结构数据转化为ndarray,但是主要区别就是当数据源是ndarray时,array仍然会copy出一个副本,占用新的内存,但asarray不会. 1.输入为列表时 ...

  4. 指针java_浅谈Java与指针 - 穿梭于偶然

    尽管在java中没有显式的使用 假设People类已经定义,请大家考虑一下面这段代码: People p1 = new People("Csyor"); People p2 = p ...

  5. 中文文本校对源码java_浅谈中文文本自动纠错在影视剧搜索中应用与Java实现

    1.背景: 这周由于项目需要对搜索框中输入的错误影片名进行校正处理,以提升搜索命中率和用户体验,研究了一下中文文本自动纠错(专业点讲是校对,proofread),并初步实现了该功能,特此记录. 2.简 ...

  6. 编译原理代码生成器java_浅谈JVM编译原理-.java文件转变为.class文件的过程

    为什么需要编译? 我们平常写代码,有规范的命名方式,都能够看得懂,但是我们写的代码计算机是看不懂的,所以需要编译,也就是一个转换的过程,如下: 1.这个是咱们平时写的代码,就比较好理解,对人友好 2. ...

  7. 单调队列java_浅谈单调队列优化dp

    单调队列,即单调的队列.有时用于优化1D/1D方程. 例题 Tyvj1305 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 输入一个长度为n的整数序列,从中 ...

  8. etag java_浅谈ETag

    HTTP/1.1中有一个Etag,用来判断请求的文件是否被修改.为什么要使用Etag呢?Etag主要网络 HTTP/1.1中有一个Etag,用来判断请求的文件是否被修改. 为什么要使用Etag呢?Et ...

  9. 业务异常 java_浅谈RxJava处理业务异常的几种方式

    本文介绍了RxJava处理业务异常的几种方式,分享给大家.具体如下: 关于异常 Java的异常可以分为两种:运行时异常和检查性异常. 运行时异常: RuntimeException类及其子类都被称为运 ...

最新文章

  1. 2022-2028年中国加气站行业市场研究及前瞻分析报告
  2. python条件赋值
  3. Android4.0与2.3的差异
  4. c语言文件查找函数fread,文件函数fread
  5. 持续集成配置之Nuget
  6. JVM的几点性能优化
  7. 卧龙吟游戏服务器不显示,卧龙吟你必须知道的隐藏特性
  8. Linux备份全攻略
  9. windows中安装64位MySQL及连接MySQL和重置MySQL密码
  10. html怎么把字转换为行内元素,什么是行内元素?
  11. Java中instanceof关键字的作用
  12. Python学习——使用ReportLab生成带表格和图文的PDF
  13. JavaScript 重定向
  14. 云原生 - 自建数据库 VS 云数据库,到底怎么选?
  15. facebook登录和分享
  16. 悟--心智成熟的旅程
  17. 计算机使人孤独英语作文,有关孤独的英语作文4篇
  18. 新产品内测!来体验超低延时的 H5 实时直播
  19. java 数组的行数和列数
  20. 云呐数据备份|什么是结构化数据

热门文章

  1. 联想和戴尔的渠道之争
  2. 《乐高EV3机器人搭建与编程》——2.5 可循环充电锂电池
  3. golang 连接mysql,连接字符串参数
  4. Nginx 40 问!
  5. centos 安装php mysql_学习centos安装php的mysql扩展
  6. 7-1 哈利·波特的考试 (25分)
  7. PV、UV的几种写法
  8. shell脚本写出一个简单的猜价格游戏
  9. esp32-pico-d4开发环境配置
  10. MySql 查询有课的学生的学号,姓名和所学的课号及成绩