【算法学习笔记】36:中国剩余定理(Chinese Remainder Theorem)求解线性同余方程组

中国剩余定理

假定存在 m 1 . . m k m_1..m_k m1..mk两两互质,中国剩余定理旨在求解这样的线性同余方程组中的 x x x
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 \equiv a_1~(mod~m_1) \\ x \equiv a_2~(mod~m_2) \\ ... \\ x \equiv a_k~(mod~m_k) xa1 (mod m1)xa2 (mod m2)...xak (mod mk)
定理给出的求解方式是,设:
M = ∏ i = 1 k m i M i = M m i M= \prod_{i=1}^{k}m_i \\ M_i = \frac{M}{m_i} M=i=1kmiMi=miM
易知 M i M_i Mi m i m_i mi互质。记 M i − 1 M_i^{-1} Mi1表示 M i M_i Mi m i m_i mi的逆,则定理给出的一个 x x x的解是:
x = ∑ i = 1 k a i ⋅ M i ⋅ M i − 1 x = \sum_{i=1}^{k}a_i \cdot M_i \cdot M_i^{-1} x=i=1kaiMiMi1

如何求 M i M_i Mi关于模 m i m_i mi的乘法逆元

前面学了快速幂求乘法逆元,但是要求模数是一个质数。但前面的线性同余方程组中只限制了不同的 m i m_i mi之间两两互质,并不要求 m i m_i mi是一个质数,所以可以用扩展欧几里得算法来求乘法逆元。

根据乘法逆元的定义:

若整数 b b b m m m互质,并且对于任意的整数 a a a,如果满足 b ∣ a b~|~a b  a,则存在一个整数 x x x,使得 a b ≡ a ⋅ x ( m o d m ) \frac{a}{b} \equiv a \cdot x(mod~m) baax(mod m),则称 x x x b b b的模 m m m乘法逆元,记为 b − 1 ( m o d m ) b^{-1}(mod~m) b1(mod m)

两边除以 a a a,再把 b b b乘到右边,就有:
b ⋅ x ≡ 1 ( m o d m ) b \cdot x \equiv 1~(mod~m) bx1 (mod m)

这正是一个特殊的线性同余方程,可以用扩展欧几里得算法求出 x x x

证明

只要证明中国剩余定理给出的解是满足线性同余方程组的一个合法解即可:
x = ∑ i = 1 k a i ⋅ M i ⋅ M i − 1 x = \sum_{i=1}^{k}a_i \cdot M_i \cdot M_i^{-1} x=i=1kaiMiMi1
只要对方程组中的每一条方程一个个带入校验即可。对于任意的第 i i i条方程, x x x m i m_i mi的结果必须是 a 1 a_1 a1

考虑到解中的第 i i i a i ⋅ M i ⋅ M i − 1 a_i \cdot M_i \cdot M_i^{-1} aiMiMi1 M i − 1 M_i^{-1} Mi1 M i M_i Mi m i m_i mi下的逆,因此它们的乘积 M i ⋅ M i − 1 M_i \cdot M_i^{-1} MiMi1 m i m_i mi一定余 1 1 1,进而这一项 a i ⋅ M i ⋅ M i − 1 a_i \cdot M_i \cdot M_i^{-1} aiMiMi1模上 m i m_i mi一定余 a i a_i ai

考虑到解中的第 j j j项( j ≠ i j \neq i j=i),由于 M j M_j Mj中一定包含了一个因子 m i m_i mi,所以这一项 a j ⋅ M j ⋅ M j − 1 a_j \cdot M_j \cdot M_j^{-1} ajMjMj1 m i m_i mi一定余 0 0 0

因此,所有项的加和模 m i m_i mi一定余 a i a_i ai,证毕。

例题:洛谷P1495 【模板】中国剩余定理(CRT)/ 曹冲养猪

模板题,注意中间结果可能会爆long long,所以要用__int128,由于是对 M i M_i Mi求逆,按照题目数据范围这个exgcdinv_rp的过程也要写成long long的。

#include <iostream>
#include <vector>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);// by + (a % b)x = d// by + (a - a/b * b) * x = d// ax + by - (a/b) * b * x = d// ax + b(y - (a/b) * x) = dy -= a / b * x;return d;
}// b和m互质求b模m的逆
LL inv_rp(LL b, LL m) {// bx = 1 (% m)// bx = 1 + my// bx + my' = 1LL x, y;exgcd(b, m, x, y);return x;
}LL crt(vector<int>& a, vector<int>& m) {LL M = 1;int n = a.size();for (int i = 0; i < n; i ++ ) {M *= m[i];}__int128 res = 0;for (int i = 0; i < n; i ++ ) {LL Mi = M / m[i];res = (res + (__int128)a[i] * Mi * inv_rp(Mi, m[i])) % M;}return (res + M) % M;
}int main() {int n; cin >> n;vector<int> a(n), b(n);for (int i = 0; i < n; i ++ ) {cin >> a[i] >> b[i];}cout << crt(b, a) << endl;return 0;
}

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

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

相关文章

stack 和 queue容器的介绍和使用

1.stack的介绍 1.1stack容器的介绍 stack容器的基本特征和功能我们在数据结构篇就已经详细介绍了&#xff0c;还不了解的uu&#xff0c; 可以移步去看这篇博客哟&#xff1a; 数据结构-栈数据结构-队列 简单回顾一下&#xff0c;重要的概念其实就是后进先出&#xff0c;栈在…

JUC--ConcurrentHashMap底层原理

ConcurrentHashMap底层原理 ConcurrentHashMapJDK1.7底层结构线程安全底层具体实现 JDK1.8底层结构线程安全底层具体实现 总结JDK 1.7 和 JDK 1.8实现有什么不同&#xff1f;ConcurrentHashMap 中的 CAS 应用 ConcurrentHashMap ConcurrentHashMap 是一种线程安全的高效Map集合…

C++17 std::variant 详解:概念、用法和实现细节

文章目录 简介基本概念定义和使用std::variant与传统联合体union的区别 多类型值存储示例初始化修改判断variant中对应类型是否有值获取std::variant中的值获取当前使用的type在variant声明中的索引 访问std::variant中的值使用std::get使用std::get_if 错误处理和访问未初始化…

计算机网络__基础知识问答

Question: 1&#xff09;在计算机网络的5层结构中&#xff0c;每一层的功能大概是什么&#xff1f; 2&#xff09;交换机的功能&#xff1f;https://www.bilibili.com/video/BV1na4y1L7Ev 3&#xff09;路由器的功能&#xff1f;https://www.bilibili.com/video/BV1hv411k7n…

NLP自然语言处理通识

目录 ELMO 一、ELMo的核心设计理念 1. 静态词向量的局限性 2. 动态上下文嵌入的核心思想 3. 层次化特征提取 1. 双向语言模型&#xff08;BiLM&#xff09; 2. 多层LSTM的层次化表示 三、ELMo的运行过程 1. 预训练阶段 2. 下游任务微调 四、ELMo的突破与局限性 1. 技术突破 2. …

在做题中学习(82):最小覆盖子串

解法&#xff1a;同向双指针——>滑动窗口 思路&#xff1a;题目要求找到s里包含t所有字符的最小子串&#xff0c;这就需要记录在s中每次查找并扩大范围时所包含进去的字符种类是否和t的相同&#xff0c;并且&#xff1a;题目提示t中会有重复字符&#xff0c;因此不能简单认…

JavaScript逆向高阶指南:突破基础,掌握核心逆向技术

JavaScript逆向高阶指南&#xff1a;突破基础&#xff0c;掌握核心逆向技术 JavaScript逆向工程是Web开发者和安全分析师的核心竞争力。无论是解析混淆代码、分析压缩脚本&#xff0c;还是逆向Web应用架构&#xff0c;掌握高阶逆向技术都将助您深入理解复杂JavaScript逻辑。本…

【deepseek】deepseek-r1本地部署-第二步:huggingface.co替换为hf-mirror.com国内镜像

一、背景 由于国际镜像国内无法直接访问&#xff0c;会导致搜索模型时加载失败&#xff0c;如下&#xff1a; 因此需将国际地址替换为国内镜像地址。 二、操作 1、使用vscode打开下载路径 2、全局地址替换 关键字 huggingface.co 替换为 hf-mirror.com 注意&#xff1a;务…

DeepSeek:突破传统的AI算法与下载排行分析

DeepSeek的AI算法突破DeepSeek相较于OpenAI以及其它平台的性能对比DeepSeek的下载排行分析&#xff08;截止2025/1/28 AI人工智能相关DeepSeek甚至一度被推上了搜索&#xff09;未来发展趋势总结 在人工智能技术飞速发展的当下&#xff0c;搜索引擎市场也迎来了新的变革。DeepS…

java 判断Date是上午还是下午

我要用Java生成表格统计信息&#xff0c;如下图所示&#xff1a; 所以就诞生了本文的内容。 在 Java 里&#xff0c;判断 Date 对象代表的时间是上午还是下午有多种方式&#xff0c;下面为你详细介绍不同的实现方法。 方式一&#xff1a;使用 java.util.Calendar Calendar 类…

Java定时任务实现方案(五)——时间轮

时间轮 这篇笔记&#xff0c;我们要来介绍实现Java定时任务的第五个方案&#xff0c;使用时间轮&#xff0c;以及该方案的优点和缺点。 ​ 时间轮是一种高效的定时任务调度算法&#xff0c;特别适用于大量定时任务的场景。时间轮的定时任务实现&#xff0c;可以使用DelayQueue…

【Matlab高端绘图SCI绘图模板】第05期 绘制高阶折线图

1.折线图简介 折线图是一个由点和线组成的统计图表&#xff0c;常用来表示数值随连续时间间隔或有序类别的变化。在折线图中&#xff0c;x 轴通常用作连续时间间隔或有序类别&#xff08;比如阶段1&#xff0c;阶段2&#xff0c;阶段3&#xff09;。y 轴用于量化的数据&#x…

【Java数据结构】了解排序相关算法

基数排序 基数排序是桶排序的扩展&#xff0c;本质是将整数按位切割成不同的数字&#xff0c;然后按每个位数分别比较最后比一位较下来的顺序就是所有数的大小顺序。 先对数组中每个数的个位比大小排序然后按照队列先进先出的顺序分别拿出数据再将拿出的数据分别对十位百位千位…

Linux的常用指令的用法

目录 Linux下基本指令 whoami ls指令&#xff1a; 文件&#xff1a; touch clear pwd cd mkdir rmdir指令 && rm 指令 man指令 cp mv cat more less head tail 管道和重定向 1. 重定向&#xff08;Redirection&#xff09; 2. 管道&#xff08;Pipes&a…

Ubuntu20.04 磁盘空间扩展教程

Ubuntu20.04 磁盘空间扩展教程_ubuntu20 gpart扩容-CSDN博客文章浏览阅读2w次&#xff0c;点赞38次&#xff0c;收藏119次。执行命令查看系统容量相关的数据&#xff1a;df -h当前容量为20G&#xff0c;已用18G&#xff08;96%&#xff09;&#xff0c;可用844M&#xff0c;可用…

使用Maxscript定义纹理贴图的方法

在3ds Max中,MaxScript 是一种用于插件编写和自动化任务的强大工具。通过MaxScript,你可以创建和操作对象、材质、灯光等等。要为材质分配纹理贴图,你可以按照以下方法来编写脚本。直接代码: myBmp = bitmaptexture filename:"D:\map001.tga" meditmaterials[1]…

每日一题-判断是否是平衡二叉树

判断是否是平衡二叉树 题目描述数据范围题解解题思路递归算法代码实现代码解析时间和空间复杂度分析示例示例 1示例 2 总结 ) 题目描述 输入一棵节点数为 n 的二叉树&#xff0c;判断该二叉树是否是平衡二叉树。平衡二叉树定义为&#xff1a; 它是一棵空树。或者它的左右子树…

Spring Data JPA 实战:构建高性能数据访问层

1 简介 1.1 Spring Data JPA 概述 1.1.1 什么是 Spring Data JPA? Spring Data JPA 是 Spring Data 项目的一部分,旨在简化对基于 JPA 的数据库访问操作。它通过提供一致的编程模型和接口,使得开发者可以更轻松地与关系型数据库进行交互,同时减少了样板代码的编写。Spri…

.NET Core 中依赖注入的使用

ASP.NET Core中服务注入的地方 在ASP.NET Core项目中一般不需要自己创建ServiceCollection、IServiceProvider。在Program.cs的builder.Build()之前向builder.Services中注入。在Controller中可以通过构造方法注入服务。 低使用频率的服务 把Action用到的服务通过Action的参…

21款炫酷烟花合集

系列专栏 《Python趣味编程》《C/C趣味编程》《HTML趣味编程》《Java趣味编程》 写在前面 Python、C/C、HTML、Java等4种语言实现18款炫酷烟花的代码。 Python Python烟花① 完整代码&#xff1a;Python动漫烟花&#xff08;完整代码&#xff09; ​ Python烟花② 完整…