当前位置: 首页 > news >正文

竞赛小算法总结(二):gcdlcm,拓展欧几里得线性同余,逆元(含代码详解)

一 gcd&lcm 

这个其实也属于是很简单但非常有必要掌握的小算法。

1. 定义

“gcd” 是 “Greatest Common Divisor” 的缩写,中文名为最大公约数 ,也称最大公因数。它指的是两个或多个整数共有约数中最大的一个。例如,对于整数 12 和 18 ,12 的约数有 (1, 2, 3, 4, 6, 12) ,18 的约数有 (1, 2, 3, 6, 9, 18) ,它们共有的约数有 (1, 2, 3, 6) ,其中最大的是 6 ,所以 12 和 18 的最大公约数(gcd )是 6 ,可表示为 (gcd(12, 18)=6) 。

2. 计算方法

这个其实也不用完全死记,大概记住现场也可以推一下。

下面是代码

/*** 使用辗转相除法计算两个整数的最大公约数(GCD)。* 原理:对于任意两个整数a和b,gcd(a, b) = gcd(b, a mod b),* 不断重复此过程直到余数为0,此时的除数即为最大公约数。* * @param a 第一个整数* @param b 第二个整数(不能为0,否则会导致除零异常)* @return a和b的最大公约数*/
public static int gcd(int a, int b) {// 计算a除以b的余数int k = a % b;// 当余数为0时,当前的除数b就是最大公约数if (k == 0) {return b;}// 否则递归计算b和余数k的最大公约数return gcd(b, k);
}

 lcm就是最小公倍数,我们直接a*b/gcd(a,b)就可以了。

代码:

public static int lcm(int a,int b) {return a*b/gcd(a,b);}

二 拓展欧几里得&线性同余

拓展欧几里得算法(Extended Euclidean Algorithm)

基本定义 拓展欧几里得算法是欧几里得算法(辗转相除法)的扩展,不仅能计算两个整数 a 和 b 的最大公约数 (d = gcd(a, b)),还能找到整数 x 和 y,使得:ax + by = d其中,x 和 y 被称为 贝祖系数(Bézout coefficients)。

贝祖系数一般用于求解求解线性不定方程ax + by = d,题目可能设计成以这个为原理的故事算法题,还有就是第三部分要讲的求模逆元。

下面来看怎么求贝祖系数:

在计算gcd时进行回溯。

// 扩展欧几里得算法 - 递归实现public static long[] extendedGCD(long a, long b) {if (b == 0) {// 终止条件:gcd(a, 0) = a,对应的贝祖系数为 (1, 0)return new long[]{a, 1, 0};} else {// 递归计算 gcd(b, a mod b)long[] result = extendedGCD(b, a % b);//接受上一层的返回值long gcd = result[0];long x = result[2];long y = result[1] - (a / b) * result[2];return new long[]{gcd, x, y};}}

三 模拟元

逆元(模运算中的乘法逆元)

在模运算中,逆元(Multiplicative Inverse) 是一个核心概念,用于解决除法问题。对于整数 a 和模数 m,若存在整数 x 使得:

则称 x 为 a 在模 m 下的逆元。逆元存在的充要条件是 a 和 m 互质(即 gcd(a, m) = 1)。

1. 扩展欧几里得算法

当 a 和 m 互质时,通过扩展欧几里得算法求解 ax + my = 1,得到的 x 即为逆元。

 // 计算模逆元:若 a 和 m 互质,返回 a 在模 m 下的逆元;否则返回 -1public static long modInverse(long a, long m) {long[] result = extendedGCD(a, m);long gcd = result[0];long x = result[1];if (gcd != 1) {// a 和 m 不互质,逆元不存在return -1;} else {// 确保逆元在 [0, m-1] 范围内return (x % m + m) % m;}}

2. 费马小定理(当 m 为质数时)

代码: 

public static long powMod(long a, long b, long mod) {long result = 1;       // 初始化结果为1while (b > 0) {        // 循环直到指数b变为0if ((b & 1) != 0) { // 检查b的二进制最低位是否为1(等价于b % 2 != 0)result = result * a % mod; // 若为1,将当前底数a乘入结果并取模}a = a * a % mod;   // 底数平方并取模b >>= 1;           // 指数右移一位(等价于b /= 2)}return result;
}

讲实话,我碰到的最多的是gcd和lcm和逆元,逆元一般用于求含除数运算的数的模,如42!/2024%100000007。

 

相关文章:

  • 大模型 Agent 中的通用 MCP 机制详解
  • 芯片跑post sim,在waveform中一般要check哪些点?
  • 【前端】es6新特性全解
  • Transformer 通关秘籍10:词向量运算:queen=king-man+wowem
  • WebFuture:瀚高数据库新建用户设置权限脚本
  • C++中回调函数详解
  • opencv(C++) 变换图像与形态学操作
  • 【Git】Commit Hash vs Change-Id
  • 一张Billing项目的流程图
  • opencv(C++) 图像滤波
  • AR眼镜+AI视频盒子+视频监控联网平台:消防救援的智能革命
  • FileZillaServer(1) -- 记录
  • 模型可信度
  • 详解Kubernetes Scheduler 的调度策略
  • 基于 STM32 的农村污水处理控制系统设计与实现
  • HTML 表单与输入:基础语法到核心应用全解析
  • Kotlin 实战:Android 设备语言与国家地区的 5 种获取方式
  • 说说 Kotlin 中的 Any 与 Java 中的 Object 有何异同?
  • 国标GB28181视频平台EasyGBS助力公交/客运搭建全场景实时监控安全管理
  • 对于ARM开发各种手册的分类
  • 娃哈哈网站建设策划书/全球网站流量排名100
  • 最新电大网站开发维护/搜索引擎优化不包括
  • 校园网络建设/南京网络推广优化哪家好
  • 专注网站建设微信开发/营销方案怎么写
  • 建网站 免费/谷歌推广怎么样
  • 网站评论怎么做的/百度广告联盟网站