初等数论--Garner‘s 算法
0. 介绍
主要通过混合积的表示来逐步求得同余方程的解。
对于同余方程
{ x ≡ v 0 ( m o d m 0 ) x ≡ v 1 ( m o d m 1 ) ⋯ x ≡ v k − 1 ( m o d m k − 1 ) \begin{equation*} \begin{cases} x \equiv v_0 \quad (\ \bmod \ m_0)\\ x \equiv v_1 \quad (\ \bmod \ m_1)\\ \cdots\\ x \equiv v_{k-1} \quad (\ \bmod \ m_{k-1})\\ \end{cases} \end{equation*} ⎩ ⎨ ⎧x≡v0( mod m0)x≡v1( mod m1)⋯x≡vk−1( mod mk−1)
满足
gcd ( m 0 , m 1 , ⋯ , m k − 1 ) = 1 \gcd(m_0,m_1, \cdots, m_{k-1})=1 gcd(m0,m1,⋯,mk−1)=1
1. 传统构造方法
M = ∏ i = 0 k − 1 m i b i = M m i , b i × i n v i ≡ 1 ( m o d m i ) x = ∑ i = 0 k − 1 v i × b i × i n v i M=\prod_{i=0}^{k-1} m_i\\ b_i=\frac{M}{m_i}, b_i\times inv_i \equiv 1 \quad(\ \bmod\ m_i)\\ x=\sum_{i=0}^{k-1} v_i \times b_i \times inv_i M=i=0∏k−1mibi=miM,bi×invi≡1( mod mi)x=i=0∑k−1vi×bi×invi
这样构造保证了 x x x的存在性,但是在计算时 b i b_i bi比较大。
下面是示例代码
template<typename T>
T exgcd(T a, T b, T &x, T &y) {if ( b == 0) {x = 1;y = 0;return a;}T x_0;T y_0;T d = exgcd( b, a % b, x_0, y_0);x = y_0;y = x_0 - (a / b) * y_0;return d;
}ll CRT(int cnt, ll *a, ll *b) {ll pia = 1;ll res = 0;for (int i = 0;i < cnt; i++) {pia *= a[i];}for (int i = 0;i < cnt; i++) {ll m = pia / a[i];ll inv, tmp;exgcd( m, a[i], inv, tmp);inv = (inv % a[i] + a[i])% a[i];__int128 sb = m * inv % pia * b[i] % pia;sb %= pia;res = (res + (ll) sb ) % pia;}return res;
}
2. Garner‘s算法
由中国剩余定理,我们知道必然存在 x < ∏ i = 0 k − 1 m i x <\prod_{i=0}^{k-1} m_i x<∏i=0k−1mi满足上面的同余方程组。
x x x的混合积表示为
x = t 0 + t 1 m 0 + ⋯ + t k − 1 ∏ i = 0 k − 2 m i x=t_0 + t_1m_0+ \cdots+t_{k-1} \prod_{i=0}^{k-2} m_i x=t0+t1m0+⋯+tk−1i=0∏k−2mi
不断对 x x x和 ∏ i = 0 s m i \prod_{i=0}^{s} m_i ∏i=0smi应用带余除数法可以证明 t i t_i ti的唯一性。
代入第一同余方程得到
t 0 ≡ v 0 ( m o d m 0 ) t_0\equiv v_0 \quad (\ \bmod \ m_0) t0≡v0( mod m0)
取 t 0 = v 0 t_0 =v_0 t0=v0, 将 x x x代入第二个方程
t 0 + t 1 m 0 ≡ v 1 ( m o d m 1 ) t 1 m 0 ≡ v 1 − t 0 ( m o d m 1 ) t 1 ≡ ( v 1 − t 0 ) m 0 − 1 ( m o d m 1 ) t_0 + t_1m_0 \equiv v_1 \quad (\ \bmod \ m_1)\\ t_1m_0\equiv v_1-t_0 \quad (\ \bmod \ m_1) \\ t_1 \equiv(v_1-t_0) m_0^{-1} \quad (\ \bmod\ m_1) t0+t1m0≡v1( mod m1)t1m0≡v1−t0( mod m1)t1≡(v1−t0)m0−1( mod m1)
我们令 X j = ∑ s = 0 j − 1 t s ∏ a = 0 s − 1 m a X_j=\sum_{s=0}^{j-1}t_s \prod_{a=0}^{s-1} m_a Xj=∑s=0j−1ts∏a=0s−1ma,也就是 x x x的混合积表示中的前 j j j
项;此时求 x x x相当于,求 X k X_k Xk。
在求 X j X_j Xj时,我们必然已经求得了 X j − 1 X_{j-1} Xj−1。
代入到第 j j j个同余方程,可以得到
X j − 1 + t j ( ∏ s = 0 j − 1 m s ) ≡ v j ( m o d m j ) t j ( ∏ s = 0 j − 1 m s ) ≡ ( v j − X j − 1 ) ( m o d m j ) t j ≡ ( v j − X j − 1 ) ( ∏ s = 0 j − 1 m s ) − 1 ( m o d m j ) X_{j-1} + t_j(\prod_{s=0}^{j-1}m_s) \equiv v_j \quad (\ \bmod \ m_j)\\ t_j(\prod_{s=0}^{j-1}m_s) \equiv (v_j - X_{j-1} ) \quad (\ \bmod \ m_j)\\ t_j \equiv(v_j-X_{j-1})(\prod_{s=0}^{j-1}m_s)^{-1} \quad (\ \bmod \ m_j) Xj−1+tj(s=0∏j−1ms)≡vj( mod mj)tj(s=0∏j−1ms)≡(vj−Xj−1)( mod mj)tj≡(vj−Xj−1)(s=0∏j−1ms)−1( mod mj)
因此我们可以递推的来求 x x x。
在应用密码学手册中给出了算法描述。
主要的解释上面已经有了,唯一需要注意的是求 ( ∏ i = 0 j − 1 m i ) − 1 ( m o d m j ) (\prod_{i=0}^{j-1} m_i) ^{-1} \quad(\ \bmod\ m_j) (∏i=0j−1mi)−1( mod mj)。
运用了乘积的逆等于逆的乘积这一性质, 证明如下
( ∏ i = 0 j − 1 m i ) ∏ i = 0 j − 1 ( m i ) − 1 ≡ ∏ i = 0 j − 1 m i m i − 1 ≡ 1 ( m o d m j ) (\prod_{i=0}^{j-1} m_i)\prod_{i=0}^{j-1}(m_i)^{-1} \equiv \prod_{i=0}^{j-1} m_i m_i^{-1} \equiv 1 \quad (\ \bmod\ m_j) (i=0∏j−1mi)i=0∏j−1(mi)−1≡i=0∏j−1mimi−1≡1( mod mj)
代码
#include <iostream>
#include <vector>using ll = long long;static constexpr int MAXN = 1e5+10;ll a[MAXN];
ll b[MAXN];template<typename T>
T exgcd(T a, T b, T &x, T &y) {if ( b == 0) {x = 1;y = 0;return a;}T x_0;T y_0;T d = exgcd( b, a % b, x_0, y_0);x = y_0;y = x_0 - (a / b) * y_0;return d;
}ll CRT_GARNER(int cnt, ll *m, ll *v)
{std::vector<ll> C(cnt, 1);for (int i = 1; i < cnt; i++) {for (int j = 0; j < i; ++j) {ll inv;ll tmp;exgcd(m[j], m[i], inv, tmp);// printf("inv of m[%d] mod m[%d]: %d\n", j, i, inv);while ( inv < 0)inv += m[i];C[ i ] = C[ i ] * inv % m[i];}}ll u = v[ 0 ];ll x = u;ll M = m[0];for (int i = 1;i < cnt; i++) {u = (v[i] - x) * C[i] % m[i];while (u < 0)u += m[ i ];x = x + u * M; M *= m[i];}return x;
}
举个例子
{ x ≡ 2 ( m o d 3 ) x ≡ 3 ( m o d 5 ) x ≡ 2 ( m o d 7 ) \begin{equation*} \begin{cases} x \equiv 2\quad(\ \bmod \ 3)\\ x \equiv 3 \quad (\ \bmod \ 5)\\ x \equiv 2 \quad (\ \bmod \ 7) \end{cases} \end{equation*} ⎩ ⎨ ⎧x≡2( mod 3)x≡3( mod 5)x≡2( mod 7)
将 x x x表示为混积的形式
x = t 0 + 2 t 1 + 15 t 2 x=t_0+2t_1+15t_2 x=t0+2t1+15t2
显然 t 0 = 2 t_0=2 t0=2;
代入到第二个同余方程
2 + 3 t 1 ≡ 3 ( m o d 5 ) 3 t 1 ≡ 1 ( m o d 5 ) t 1 ≡ 3 − 1 ( m o d 5 ) 2+3t_1 \equiv 3 \quad (\ \bmod \ 5)\\ 3t_1 \equiv1 \quad (\ \bmod \ 5)\\ t_1\equiv3^{-1} \quad (\ \bmod\ 5)\\ 2+3t1≡3( mod 5)3t1≡1( mod 5)t1≡3−1( mod 5)
3 − 1 ( m o d 5 ) 3^{-1} \quad (\ \bmod \ 5) 3−1( mod 5)可由扩展欧几里得算法求得
3 × 2 − 1 × 5 = 1 3 − 1 ( m o d 5 ) = 2 3 \times 2 -1 \times 5=1\\ 3^{-1} \quad( \ \mod \ 5) =2 3×2−1×5=13−1( mod 5)=2
因此 t 2 = 2 t_2=2 t2=2。
代入第三个同余方程
2 + 3 × 2 + 15 t 2 = 8 + 15 t 2 15 t 2 + 8 ≡ 2 ( m o d 7 ) 15 t 2 ≡ 1 ( m o d 7 ) t 2 ≡ 15 − 1 ( m o d 7 ) 2+3\times2+15t_2=8+15t_2\\ 15t_2+8 \equiv2 \quad (\ \bmod\ 7)\\ 15t_2 \equiv1 \quad ( \bmod\ 7)\\ t_2\equiv15^{-1}\quad(\ \bmod \ 7) 2+3×2+15t2=8+15t215t2+8≡2( mod 7)15t2≡1(mod 7)t2≡15−1( mod 7)
同样是利用扩展欧几里得求出逆元
t 2 ≡ 1 ( m o d 7 ) t_2 \equiv 1 \quad (\ \bmod \ 7) t2≡1( mod 7)
代入到混合积形式
x = 8 + 15 = 23 x=8+ 15=23 x=8+15=23
参考
oi-wiki-crt
handbook-of-applied-crypho
相关文章:

初等数论--Garner‘s 算法
0. 介绍 主要通过混合积的表示来逐步求得同余方程的解。 对于同余方程 { x ≡ v 0 ( m o d m 0 ) x ≡ v 1 ( m o d m 1 ) ⋯ x ≡ v k − 1 ( m o d m k − 1 ) \begin{equation*} \begin{cases} x \equiv v_0 \quad (\ \bmod \ m_0)\\ x \equiv v_1 \quad (\ \bmod \ m_1)…...

NV211NV212美光科技颗粒NV219NV220
NV211NV212美光科技颗粒NV219NV220 技术架构解析:从颗粒到存储系统 近期美光科技发布的NV211、NV212、NV219、NV220系列固态颗粒,凭借其技术突破引发行业关注。这些颗粒基于176层QLC堆叠工艺,单Die容量预计在2026年可达1Tb,相当…...

SQL解析工具JSQLParser
目录 一、引言二、JSQLParser常见类2.1 Class Diagram2.2 Statement2.3 Expression2.4 Select2.5 Update2.6 Delete2.7 Insert2.8 PlainSelect2.9 SetOperationList2.10 ParenthesedSelect2.11 FromItem2.12 Table2.13 ParenthesedFromItem2.14 SelectItem2.15 BinaryExpressio…...

Wave Terminal + Cpolar:SSH远程访问的跨平台实战+内网穿透配置全解析
文章目录 前言1. Wave Terminal安装2. 简单使用演示3. 连接本地Linux服务器3.1 Ubuntu系统安装ssh服务3.2 远程ssh连接Ubuntu 4. 安装内网穿透工具4.1 创建公网地址4.2 使用公网地址远程ssh连接 5. 配置固定公网地址 前言 各位开发者朋友,今天为您介绍一款颠覆性操…...

html使用JS实现账号密码登录的简单案例
目录 案例需求 思路 错误案例及问题 修改思路 案例提供 所需要的组件 <input>标签,<button>标签,<script>标签 详情使用参考:HTML 教程 | 菜鸟教程 案例需求 编写一个程序,最多允许用户尝试登录 3 次。…...
sorted() 函数和sort()函数的区别
在Python中,sorted() 函数和列表的 sort() 方法都用于排序,但它们之间有一些关键的区别: 返回值: sorted():返回一个新的列表,包含所有排序后的元素,原始列表不会被修改。sort():对列…...
Solr搜索:比传统数据库强在哪?
Solr 是一个基于 Apache Lucene 的开源搜索平台,广泛用于全文检索和数据分析。与传统的关系型数据库查询相比,Solr 在某些方面具有明显的优势,特别是在处理大规模文本数据和复杂的搜索需求时。以下是 Solr 相对于传统数据库查询的主要优势&am…...

【数据集】基于ubESTARFM法的100m 地温LST数据集(澳大利亚)
目录 数据概述一、输入数据与处理二、融合算法1. ESTARFM(Enhanced STARFM)2. ubESTARFM(Unbiased ESTARFM)代码实现数据下载参考根据论文《Generating daily 100 m resolution land surface temperature estimates continentally using an unbiased spatiotemporal fusion…...

51c自动驾驶~合集55
我自己的原文哦~ https://blog.51cto.com/whaosoft/13935858 #Challenger 端到端碰撞率暴增!清华&吉利,框架:低成本自动生成复杂对抗性驾驶场景~ 自动驾驶系统在对抗性场景(Adversarial Scenarios)中的可靠性是安全落…...

【前端基础】Promise 详解
文章目录 什么是 Promise?为什么要使用 Promise?创建 Promise消费 Promise (使用 Promise)1. .then(onFulfilled, onRejected)2. .catch(onRejected)3. .finally(onFinally) Promise 链 (Promise Chaining)Promise 的静态方法1. Promise.resolve(value)2…...

高性能管线式HTTP请求
高性能管线式HTTP请求:原理、实现与实践 目录 高性能管线式HTTP请求:原理、实现与实践 1. HTTP管线化的原理与优势 1.1 HTTP管线化的基本概念 关键特性: 1.2 管线化的优势 1.3 管线化的挑战 2. 高性能管线式HTTP请求的实现方案 2.1 技术选型与工具 2.2 Java实现:…...
c/c++的opencv膨胀
使用 OpenCV (C) 进行图像膨胀操作详解 图像膨胀 (Dilation) 是形态学图像处理中的另一种基本操作,与腐蚀操作相对应。它通常用于填充图像中的小孔洞、连接断开的物体部分、以及加粗二值图像中的物体。本文将详细介绍膨胀的原理,并演示如何使用 C 和 Op…...
react native搭建项目
React Native 项目搭建指南 React Native 是一个使用 JavaScript 和 React 构建跨平台移动应用的框架。以下是搭建 React Native 项目的详细步骤: 1. 环境准备 安装 Node.js 下载并安装 Node.js (推荐 LTS 版本) 安装 Java Development Kit (JDK) 对于 Androi…...

【CSS】九宫格布局
CSS Grid布局(推荐) 实现代码: <!doctype html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0"…...

Python用Transformer、Prophet、RNN、LSTM、SARIMAX时间序列预测分析用电量、销售、交通事故数据
原文链接: tecdat.cn/?p42219 在数据驱动决策的时代,时间序列预测作为揭示数据时序规律的核心技术,已成为各行业解决预测需求的关键工具。从能源消耗趋势分析到公共安全事件预测,不同领域的数据特征对预测模型的适应性提出了差异…...

java基础(面向对象进阶高级)泛型(API一)
认识泛型 泛型就等于一个标签(比如男厕所和女厕) 泛型类 只能加字符串: 把别人写好的东西,自己封装。 泛型接口 泛型方法、泛型通配符、上下限 怎么解决下面的问题? API object类 toString: equals: objects类 包装类 为什么上面的Integer爆红…...

学习心得(17--18)Flask表单
一. 认识表单:定义表单类 password2中末端的EqualTo(password)是将密码2与密码1进行验证,看是否相同 二.使用表单: 运行 如果遇到这个报错,就在该页面去添加 下面是举例: 这就是在前端的展示效…...
AI测试和敏捷测试有什么联系与区别?
AI测试与敏捷测试作为软件质量保障领域的两种重要方法,既有紧密联系也存在显著区别。以下是两者的联系与区别分析: 一、联系 共同目标:提升测试效率与质量 敏捷测试强调通过快速迭代、持续反馈和团队协作确保交付价值,而AI测试通…...

微信小程序进阶第2篇__事件类型_冒泡_非冒泡
在小程序中, 事件分为两种类型: 冒泡事件, 当一个组件上的事件被触发后,该事件会向父节点传递非冒泡事件, 当一个组件上的事件被触发后, 该事件不会向父节点传递。 一 冒泡事件 tap, touchst…...

电机控制学习笔记
文章目录 前言一、电机二、编码器三、开环控制和闭环控制总结 前言 学习了解电机控制技术的一些原理和使用的方法。 一、电机 直流有刷电机 操作简单 使用H桥驱动直流有刷电机 直流有刷电机驱动板 电压检测 电流检测以及温度检测 直流无刷电机 使用方波或者正弦波进行换向…...
什么是前端工程化?它有什么意义
前端工程化是指通过工具、流程和规范,将前端开发从手工化、碎片化的模式转变为系统化、自动化和标准化的生产过程。其核心目标是 提升开发效率、保障代码质量、增强项目可维护性,并适应现代复杂 Web 应用的需求。 一、前端工程化的核心内容 1. 模块化开发 代码模块化:使用 …...

企业网站架构部署与优化-Nginx性能调优与深度监控
目录 #1.1Nginx性能调优 1.1.1更改进程数与连接数 1.1.2静态缓存功能设置 1.1.3设置连接超时 1.1.4日志切割 1.1.5配置网页压缩 #2.1nginx的深度监控 2.1.1GoAccess简介 2.1.2nginx vts简介 1.1Nginx性能调优 1.1.1更改进程数与连接数 (1)进程数 进程数…...

行列式的线性性质(仅限于单一行的加法拆分)
当然可以,以下是经过排版优化后的内容,保持了原始内容不变,仅调整了格式以提升可读性: 行列式的线性性质(加法拆分) 这个性质说的是:如果行列式的某一行(或某一列)的所有…...

JAVA基础编程练习题--50道
一:循环结构 1.1 for循环 水鲜花数 (1)题目 (2)难点 如何获取三位数的个位数 如何计算一个数的立方 判断两数值是否相等 (3)代码 最大公约数 (1)题目 (2&…...

leetcode 93. Restore IP Addresses
题目描述 93. Restore IP Addresses 代码 回溯法 class Solution {vector<string> res; public:vector<string> restoreIpAddresses(string s) {string IP;int part 0;backtracking(s,0,IP,part);return res;}void backtracking(const string &s,int start…...
【东枫科技】基于Docker,Nodejs,GitSite构建一个KB站点
Docker 安装桌面版本,安装Node镜像 运行node镜像 需求 和外部的某个文件夹地址可以绑定端口可以绑定,方便server的访问 docker run -itd --name node-test -v C:/Users/fs/Documents/GitHub:/home/node -p 3000:3000 node进入终端 docker exec -it …...

pytest+allure+allure-pytest 报告输出遇到的问题汇总
文章目录 前言问题一:module allure has no attribute severity_level问题二:ERROR:file or directory not found: ‐vs问题三:生成的 html 报告是空的,明明有测试用例执行完成,但报告没有显示数据 前言 pytestallure…...
Python基础语法(十四):Python常用内置模块及功能
Python标准库提供了丰富的内置模块,无需额外安装即可使用。以下是按功能分类的常用内置模块及其核心功能: 一、文件与操作系统交互 1. os 模块 功能:操作系统接口常用方法:os.getcwd() # 获取当前工作目录 os.listdir() …...

【Opencv+Yolo】_Day1图像基本处理
目录 一、计算机中的视觉: 二、Opencv基本操作: 图片基础处理: 视频基本处理: 图像截取(截取,合并,只保留一个元素) 图像填充 数值计算 图像融合 阈值判断 图像平滑 图像腐…...
MySQL各种日志类型介绍
概述 MySQL 提供了多种日志类型,用于记录数据库的运行状态、操作历史和错误信息等,这些日志对于故障排查、性能优化、安全审计和数据恢复等具有重要作用。以下是 MySQL 中常见的日志类型及其详细介绍资料已经分类整理好:https://pan.quark.c…...