Acwing 扩展欧几里得算法

news2024/12/27 2:06:51

1.扩展欧几里得算法

回忆:求最大公约数中学过欧几里得算法(辗转相除法):gcd(a,b) == gcd(b, a % b);
裴蜀定理:对于任意正整数a,b,那么一定存在非零整数x,y,使得ax+by=gcd(a,b);
扩展欧几里得算法:就是求解上面裴蜀定理中a和b的系数x,y;具体怎么求?

  • 首先若b=0,那么显然gcd(a,0)=a,则可得x=1,y=0;
  • 若a,b都不为0,结合欧几里得算法gcd(a,b) == gcd(b, a % b),那么ax+by=gcd(a,b)===>b*x+(a%b)*y=gcd(a,b),但在递归的过程中a的系数由x变为y,b的系数由y变为x,所以在递归过程的传入参数时因调换x和y的位置,变为b*y+(a%b)*x=gcd(a,b),下面的代码会体现;
  • 设gcd(a,b)=d,那么继续推理得到
  • 在这里插入图片描述
    即可求出系数,注意x和y可能不是唯一的。

Acwing 877.扩展欧几里得算法
在这里插入图片描述

具体实现代码(详解版):

#include <iostream>

using namespace std;

// 扩展欧几里得算法函数
int exgcd(int a, int b, int &x, int &y) {
    if (!b) {
        x = 1;  // 基本情况:如果 b == 0,x 为 1
        y = 0;  // y 为 0,因为 a * 1 + b * 0 = a
        return a; // 返回 gcd(a, b)
    }
    int d = exgcd(b, a % b, y, x); // 递归调用
    y -= (a / b) * x; // 使用之前的 x 更新 y
    return d; // 返回 gcd
}

int main() {
    int n;
    cin >> n; 
    while (n--) {
        int a, b, x, y;
        cin >> a >> b; 
        exgcd(a, b, x, y); // 调用扩展欧几里得算法
        cout << x << ' ' << y << endl; // 输出系数 x 和 y
    }
    return 0; 
}

下面给出一个扩展欧几里得算法的应用。

2.Acwing 878.线性同余方程

在这里插入图片描述
实现思路:对于(a*x) mod m=b,求解x。

  • 恒等变形可以得a*x=m*y'+b=>a*x-m*y'=b=>a*x+m*y=b,此时就形似扩展欧几里得算法,则由裴蜀定理可知a*x+m*y=gcd(a,m)必然有解,假如b是gcd(a,m)的倍数,即必然存在这样的x和y,使所求等式有解,只需等式两边扩大相应的倍数即可。此时x=x*(b/gcd(a,m))
  • 这里最后**x*(b/gcd(a,m))%m**是为了得到最小的解,因为x的通解有无数个,防止超出int范围,就取一个最小的

具体实现代码(详解版):

#include <iostream>

using namespace std;
typedef long long LL; // 定义 LL 为 long long 类型

// 扩展欧几里得算法函数
int exgcd(int a, int b, int &x, int &y) {
    if (!b) {
        x = 1;  // 基本情况:如果 b == 0,x 为 1
        y = 0;  // y 为 0,因为 a * 1 + b * 0 = a
        return a; // 返回 gcd(a, b)
    }
    int d = exgcd(b, a % b, y, x); // 递归调用
    y -= (a / b) * x; // 使用之前的 x 更新 y
    return d; // 返回 gcd
}

int main() {
    int n;
    cin >> n; 
    while (n--) {
        int a, b, m, x, y;
        cin >> a >> b >> m; 
        int d = exgcd(a, m, x, y); // 调用扩展欧几里得算法
        if (b % d == 0) { // 如果 b 是 d 的倍数
            cout << (LL)x * (b / d) % m << endl; // 输出最小解
        } else {
            puts("impossible"); // 输出 "impossible"
        }
    }
    return 0; 
}

3.中国剩余定理

x 有 k 个两两互质的数 m 1 、 m 2 、 … 、 m k 给定线性同余方程组  x ≡ a 1 ( m o d   m 1 ) 、 x ≡ a 2 ( m o d   m 2 ) 、 … 、 x ≡ a k ( m o d   m k ) 求 x 解法: 令 M = m 1 × m 2 × ⋯ × m k , M i = M m i ,用 M i − 1 表示 M i 模的逆 ( 求 M i − 1 : M i × M i − 1 ≡ 1 ( m o d   m i ) ,实质就是用扩展欧几里得求一个特殊的线性同余方程 : a × x ≡ 1 ( m o d   m ) ) 则 x = a 1 × M 1 × M 1 − 1 + a 2 × M 2 × M 2 − 1 + ⋯ + a k × M k × M k − 1 可以验证 x 为该线性同余方程组的解(略) x 有k个两两互质的数m_{1}、m_{2}、\dots 、m_{k}\\给定线性同余方程组\ x\equiv a_{1}(mod\ m_{1})、x\equiv a_{2}(mod\ m_{2})、… 、x\equiv a_{k}(mod\ m_{k})\\\\求x解法:\\令M=m_{1}\times m_{2}\times \dots \times m_{k},M_{i}=\frac{M}{m_{i}},用M_{i}^{-1}表示M_{i} 模的逆 \\(求M_{i}^{-1}:M_{i} \times M_{i}^{-1} \equiv 1 (mod \ m_{i}),实质就是用扩展欧几里得求一个特殊的线性同余方程:a \times x\equiv 1 (mod \ m))\\则x=a_{1}\times M_{1} \times M_{1}^{-1} + a_{2}\times M_{2} \times M_{2}^{-1} + \dots + a_{k}\times M_{k} \times M_{k}^{-1}\\可以验证x为该线性同余方程组的解(略) xk个两两互质的数m1m2mk给定线性同余方程组 xa1(mod m1)xa2(mod m2)xak(mod mk)x解法:M=m1×m2××mkMi=miM,用Mi1表示Mi模的逆(Mi1Mi×Mi11(mod mi),实质就是用扩展欧几里得求一个特殊的线性同余方程:a×x1(mod m))x=a1×M1×M11+a2×M2×M21++ak×Mk×Mk1可以验证x为该线性同余方程组的解(略)

Acwing 204.表达整数的奇怪方式
在这里插入图片描述
求解推导:
公式
1. 对于两个式子,考虑将其合并: x ≡   m 1 ( % a 1 ) x ≡   m 2 ( % a 2 ) 则有: x = k 1 ∗ a 1 + m 1 , x = k 2 ∗ a 2 + m 2 , 进一步联立上面两式: k 1 ∗ a 1 + m 1 = k 2 ∗ a 2 + m 2 = = > k 1 ∗ a 1 + k 2 ∗ ( − a 2 ) = m 2 − m 1 . . . ① 也就是我们要找到一个最小的 k 1 , k 2 ,使得等式成立 ( 因为要求 x 最小,而 a 和 m 都是正数 ) 2. 对 a 1 和 a 2 使用扩展欧几里得得到最小公约数 d = g c d ( a 1 , − a 2 ) 即 k 1 ∗ a 1 + k 2 ∗ a 2 = d = g c d ( a 1 , − a 2 ) . . . ② 此时对于①和②式就出现了之前求线性同余方程的情况,即 m 2 − m 1 是 d 的倍数时 ( d ∣ m 2 − m 1 ) 方程有解 ②式两边乘 m 2 − m 1 d 就转化为①式 即 k 1 ∗ a 1 ∗ m 2 − m 1 d + k 2 ∗ a 2 ∗ m 2 − m 1 d = m 2 − m 1 3. 有解的情况下得到一组解 : k 1 = k 1 ∗ m 2 − m 1 d ,   k 2 = k 2 ∗ m 2 − m 1 d , 注意这里 k 就表示特解 4. 找最小正整数解:模尽倍数后,剩下的余数就是最小正整数解 k 1 = k 1   %   a b s ( a 2 d ) , k 2 = k 2   %   a b s ( a 1 d ) 5. 找满足方程的所有解 将一组方程的解带回方程: k 1 ∗ a 1 + k 2 ∗ a 2 = c 等式左边加减 a 1 ∗ a 2 d , 方程右边不变,可得: k 1 ∗ a 1 + k 2 ∗ a 2 + a 1 ∗ a 2 d − a 2 ∗ a 1 d = ( k 1 + a 2 d ) ∗ a 1 + ( k 2 − a 1 d ) ∗ a 2 = c 于是得到所有解集: k 1 = k 1 + a 2 d ∗ k , k 2 = k 2 − a 1 d ∗ k ​ 6. 再代入 k 1 , k 2 得新的 x 为: x = ( k 1 + a 2 d ∗ k ) ∗ a 1 + m 1 = k 1 ∗ a 1 + m 1 + a 1 ∗ a 2 d ∗ k 令新的 a 1 ′ = a 1 ∗ a 2 d , 新的 m 1 ′ = k 1 ∗ a 1 + m 1 那么 x = a 1 ′ ∗ k + m 1 ′ , 这时就又回到了第一步,至此完成两个式子的合并 , 后续再来一个 a 3 , m 3 同理继续合并, n 个式子进行 n − 1 次合并得到最终式 1.对于两个式子,考虑将其合并:\\ x\equiv \ m_1 (\% a_1 )\\ x\equiv \ m_2 (\% a_2 )\\则有:x=k_1*a_1+m_1,x=k_2*a_2+m_2,\\进一步联立上面两式:k_1*a_1+m_1=k_2*a_2+m_2==>\mathbf {k_1*a_1+k_2*(-a_2)=m_2-m_1...①}\\也就是我们要找到一个最小的k_1,k_2,使得等式成立(因为要求x最小,而a和m都是正数)\\ \\2.对a_1和a_2使用扩展欧几里得得到最小公约数d=gcd(a_1,-a_2)\\即\mathbf {k_1*a_1+k_2*a_2=d=gcd(a_1,-a_2)...②}\\此时对于①和②式就出现了之前求线性同余方程的情况,即m_2-m_1是d的倍数时(d|m_2-m_1)方程有解\\②式两边乘\frac{m_2-m_1}{d}就转化为①式\\即\mathbf {k_1*a_1* \frac{m_2-m_1}{d} +k_2*a_2* \frac{m_2-m_1}{d}=m_2-m_1}\\ \\3.有解的情况下得到一组解:\\ \mathbf {k_1=k_1* \frac{m_2-m_1}{d} ,\ k_2=k_2* \frac{m_2-m_1}{d}},注意这里k就表示特解\\ \\4.找最小正整数解:模尽倍数后,剩下的余数就是最小正整数解\\k_1=k_1\ \% \ abs(\frac{a_2}{d}),k_2=k_2\ \% \ abs(\frac{a_1}{d})\\ \\5.找满足方程的所有解\\将一组方程的解带回方程:k_1*a_1+k_2*a_2=c\\等式左边加减\frac{a_1*a_2}{d},方程右边不变,可得:\\k_1*a_1+k_2*a_2+a_1*\frac{a_2}{d}-a_2*\frac{a_1}{d}=(k_1+\frac{a_2}{d})*a_1+(k_2-\frac{a_1}{d})*a_2=c\\ \mathbf {于是得到所有解集:k_1=k_1+\frac{a_2}{d}*k,k_2=k_2-\frac{a_1}{d}*k}​\\ \\6.再代入k_1,k_2得新的x为:x=(k_1+\frac{a_2}{d}*k)*a_1+m_1\\=k_1*a_1+m_1+\frac{a_1*a_2}{d}*k\\令新的a_1^{'}=\frac{a_1*a_2}{d},新的m_1^{'}=k_1*a_1+m_1\\那么x=a_1^{'}*k+m_1^{'},这时就又回到了第一步,至此完成两个式子的合并,\\后续再来一个a_3,m_3同理继续合并,n个式子进行n-1次合并得到最终式 1.对于两个式子,考虑将其合并:x m1(%a1)x m2(%a2)则有:x=k1a1+m1,x=k2a2+m2,进一步联立上面两式:k1a1+m1=k2a2+m2==>k1a1+k2(a2)=m2m1...也就是我们要找到一个最小的k1,k2,使得等式成立(因为要求x最小,而am都是正数)2.a1a2使用扩展欧几里得得到最小公约数d=gcd(a1,a2)k1a1+k2a2=d=gcd(a1,a2)...此时对于式就出现了之前求线性同余方程的情况,即m2m1d的倍数时(dm2m1)方程有解式两边乘dm2m1就转化为k1a1dm2m1+k2a2dm2m1=m2m13.有解的情况下得到一组解:k1=k1dm2m1, k2=k2dm2m1,注意这里k就表示特解4.找最小正整数解:模尽倍数后,剩下的余数就是最小正整数解k1=k1 % abs(da2),k2=k2 % abs(da1)5.找满足方程的所有解将一组方程的解带回方程:k1a1+k2a2=c等式左边加减da1a2,方程右边不变,可得:k1a1+k2a2+a1da2a2da1=(k1+da2)a1+(k2da1)a2=c于是得到所有解集:k1=k1+da2k,k2=k2da1k6.再代入k1,k2得新的x为:x=(k1+da2k)a1+m1=k1a1+m1+da1a2k令新的a1=da1a2,新的m1=k1a1+m1那么x=a1k+m1,这时就又回到了第一步,至此完成两个式子的合并,后续再来一个a3,m3同理继续合并,n个式子进行n1次合并得到最终式

具体实现代码(详解版):

#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

// 扩展欧几里得算法函数
LL exgcd(LL a, LL b, LL &x, LL &y) {
    if (!b) {
        x = 1, y = 0;
        return a;
    }
    LL d = exgcd(b, a % b, y, x); // 递归调用
    y -= a / b * x; // 更新 y
    return d; // 返回 gcd(a, b)
}

int main() {
    int n;
    cin >> n; // 读取方程的数量
    bool has_answer = true; // 假设有解
    LL a1, m1;
    cin >> a1 >> m1; // 读取第一个方程的系数 a1 和余数 m1
    
    // 迭代处理剩余的方程
    for (int i = 0; i < n - 1; i++) {
        LL a2, m2;
        cin >> a2 >> m2; // 读取下一个方程的系数 a2 和余数 m2
        
        LL k1, k2;
        LL d = exgcd(a1, a2, k1, k2); // 计算 a1 和 a2 的 gcd
        
        // 如果 m2 - m1 不能被 gcd(a1, a2) 整除,则无解
        if ((m2 - m1) % d) {
            has_answer = false;
            break;
        }
        
        // 更新 k1,找到合适的 k1
        k1 *= (m2 - m1) / d;
        LL t = a2 / d;
        k1 = (k1 % t + t) % t; // 使 k1 是模 t 的正数解
        
        // 更新 m1 和 a1
        m1 = a1 * k1 + m1;
        a1 = abs(a1 / d * a2); // 更新 a1 为最小公倍数
    }
    
    // 输出结果
    if (has_answer) {
        cout << (m1 % a1 + a1) % a1 << endl; // 输出最小非负解
    } else {
        puts("-1"); // 无解
    }
    
    return 0;
}

以上就是扩展欧几里得算法及其应用,关键是掌握欧几里得算法,应用可能推导较难,见机行事~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2180935.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

锁相环PLL 学习笔记(一)

锁相环&#xff08;Phase-Locked Loop, PLL&#xff09; 一、基本概念及原理 是一个能够比较输出与输入相位差的反馈系统&#xff0c;利用外部输入的参考信号控制环路内部振荡信号的频率和相位&#xff0c;使振荡信号同步至参考信号。 下图为简单锁相环的结构示意图&#xf…

【工欲善其事】巧用 Sublime Text 生成带格式的 HTML 片段

文章目录 【工欲善其事】巧用 Sublime Text 生成带格式的 HTML 片段1 问题由来2 操作流程步骤1&#xff1a;打开代码片段定制页步骤2&#xff1a;在新标签页输入定制 XML步骤3&#xff1a;保存定义内容步骤4&#xff1a;功能测试 3 拓展 【工欲善其事】巧用 Sublime Text 生成带…

什么是前端开发 ?

每当我们访问网页时&#xff0c;为什么会有这么多样的图片、视频、动画、各种各样的元素呢&#xff1f;下面将为你揭晓&#xff01; 一、 前端世界的基石 一切始于用户在浏览器地址栏输入一串字符&#xff0c;敲下回车。看似简单的动作&#xff0c;却开启了一段奇妙的旅程。 …

实时美颜功能技术揭秘:视频美颜SDK与API的技术剖析

当下&#xff0c;用户希望在视频直播中呈现出最佳状态&#xff0c;这推动了视频美颜SDK和API的迅速发展。本文将深入剖析这项技术的核心原理、应用场景以及未来趋势。 一、实时美颜技术的基本原理 在实现这些效果的过程中&#xff0c;视频美颜SDK通常会使用以下几种技术&…

海信新风空调小氧吧X7:解锁母婴级标准认证的防直吹神器

随着智能科技推进&#xff0c;人们对空调产品的需求&#xff0c;早已超越温度调节范畴&#xff0c;注重追求舒适体验与健康生态。如何让用户拥抱好空气&#xff0c;体验呼吸舒适感&#xff1f;近日&#xff0c;海信空调发布产品预告&#xff0c;10月1日&#xff0c;海信新风空调…

Unity实战案例全解析:RTS游戏的框选和阵型功能(5)阵型功能 优化

前篇&#xff1a;Unity实战案例全解析&#xff1a;RTS游戏的框选和阵型功能&#xff08;4&#xff09;阵型功能-CSDN博客 本案例来源于unity唐老狮&#xff0c;有兴趣的小伙伴可以去泰克在线观看该课程 我只是对重要功能进行分析和做出笔记分享&#xff0c;并未无师自通&#x…

产品管理- 互联网产品(6):产品测试

可用性测试 招募有代表性用户作为测试代表参与者&#xff0c;评估某产品符合特定可用性及符合程度。以具有代表性的用户为测试样本。 测试中多关注用户表情与动作。多鼓励与测试的用户更多的操作以用户角度发现问题。同时要做好询问工作&#xff0c;耐心聆听用户的意见&#x…

CSS面试真题 part1

CSS面试真题 part1 1、说说你对盒子模型的理解2、谈谈你对BFC的理解3、什么是响应式设计&#xff1f;响应式设计的基本原理是什么&#xff1f;如何做&#xff1f;4、元素水平垂直居中的方法有哪些&#xff1f;如果元素不定宽高呢&#xff1f;5、如何实现两栏布局&#xff0c;右…

Java数组使用练习(完)

目录 1.数组的使用 1.1数组拷贝native 1.2二分查找 1.3数组元素的平均值 1.4数组元素的排序 1.5其他的常用的方法 1.6冒泡排序实现 1.7数组元素的逆置实现 1.8二维数组 2.关于数组的课后练习 2.1改变数组原有的元素的值 2.2奇数在前&#xff0c;偶数在后 2.3判断目…

Axure大屏可视化模板在不同领域中的实际应用案例

一、农业领域 案例背景&#xff1a; 智慧农业是当前农业发展的重要趋势&#xff0c;通过物联网、大数据等技术手段&#xff0c;实现农业生产的智能化管理。Axure大屏可视化模板在智慧农业平台的建设中发挥了重要作用。 实际应用&#xff1a; 农田环境监控&#xff1a;通过Axu…

TI DSP TMS320F280025 Note13:CPUtimer定时器原理分析与使用

TMS320F280025 CPUtimer定时器原理分析与使用 ` 文章目录 TMS320F280025 CPUtimer定时器原理分析与使用框图分析定时器中断定时器使用CPUtimers.cCPUtimers.h框图分析 定时器框图如图所示 定时器有一个预分频模块和一个定时/计数模块, 其中预分频模块包括一个 16 位的定时器分…

基于单片机的家用安防报警系统设计

本设计基于STM32F103单片机作为系统主控核心&#xff0c;通过DS18B20温度传感器和MQ烟雾传感器对家庭环境的温度和烟雾浓度进行检测实现火灾预警的设计要求&#xff0c;当检测数据异常时激发报警提示。系统采用红外传感器对家庭环境中是否有盗贼进入实现检测&#xff0c;当出现…

单臂路由详解

目录 单臂路由概念 单臂路由实验 路由器配置 交换机配置 实验验证 基于Eth-Trunk的单臂路由 路由器配置 交换机配置 实验验证 单臂路由概念 单臂路由技术能让路由器的一个物理接口对应不同VLAN数据的实质是把物理接口分成若干个子接口&#xff0c;这些子接口通过封装…

前端算法合集-1(含面试题)

(这是我面试一家中厂公司的二面算法题) 数组去重并按出现次数排序 题目描述: 给定一个包含重复元素的数组&#xff0c;请你编写一个函数对数组进行去重&#xff0c;并按元素出现的次数从高到低排序。如果次数相同&#xff0c;则按元素值从小到大排序。 let arr [2, 11,10, 1…

windows配置C++编译环境和VScode C++配置(保姆级教程)

1.安装MinGW-w64 MinGW-w64是一个开源的编译器套件,适用于Windows平台,支持32位和64位应用程序的开发。它包含了GCC编译器、GDB调试器以及其他必要的工具,是C++开发者在Windows环境下进行开发的重要工具。 我找到了一个下载比较快的链接:https://gitcode.com/open-source-…

表格控件QTableWidget

下面说一下表格的常用方法 行列数目、行表头、列表头 行表头&#xff1a;就是表格控件的第一行&#xff0c;用于设置每一列的标题 列表头&#xff1a;就是表格控件的第一列&#xff0c;用于设置每一行的标题&#xff0c;通常缺省则默认显示行号 设置和获取行列的数目 在添…

【CKA】一、基于角色的访问控制-RBAC

1、基于角色的访问控制-RBAC 1. 考题内容&#xff1a; 2. 答题思路&#xff1a; 这道题就三条命令&#xff0c;建议直接背熟就行。 也可以查看帮助 kubectl create clusterrole -h kubectl create serviceaccount -h kubectl create rolebinding -h 注意&#xff1a; 1、资…

Prisma 基本使用

以下内容官方文档都有&#xff0c;特此记录便于快速查阅文档。 Prisma CLI 作为开发依赖项安装到项目中 npm install prisma --save-devPrisma 配合 ts 很强大&#xff0c;所有我们可以结合 ts 一起使用&#xff1a; npm install typescript ts-node types/node --save-dev n…

对于“言而有信”之己见

大凡古文爱好者&#xff0c;都知晓《论语》中的“仁、义、礼、智、信”这五大做人的常理。 网络图片 儒家对于“言而有信”的认识十分理性&#xff0c;尤其是其中的“信”字&#xff0c;对于当今社会成堆“老赖”&#xff0c;简直就是直接打在他们脸上的大巴掌。​ 古人对于“…

强化学习-python案例

强化学习是一种机器学习方法&#xff0c;旨在通过与环境的交互来学习最优策略。它的核心概念是智能体&#xff08;agent&#xff09;在环境中采取动作&#xff0c;从而获得奖励或惩罚。智能体的目标是最大化长期奖励&#xff0c;通过试错的方式不断改进其决策策略。 在强化学习…