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

【算法学习笔记】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) = d
	y -= a / b * x;
	return d;
}

// b和m互质求b模m的逆
LL inv_rp(LL b, LL m) {
	// bx = 1 (% m)
	// bx = 1 + my
	// bx + my' = 1
	LL 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.kler.cn/a/522200.html

相关文章:

  • Windows11无法打开Windows安全中心主界面
  • (2)SpringBoot自动装配原理简介
  • 四.3 Redis 五大数据类型/结构的详细说明/详细使用( hash 哈希表数据类型详解和使用)
  • 设计模式-建造者模式、原型模式
  • 【深度学习】 UNet详解
  • C#高级:常用的扩展方法大全
  • 06-机器学习-数据预处理
  • Vision Mamba在AMD GPU上使用ROCm
  • c语言版贪吃蛇(Pro Max版)附源代码
  • 题解 信息学奥赛一本通/AcWing 1118 分成互质组 DFS C++
  • 010 mybatis-PageHelper分页插件
  • 精通PCIe技术:协议解析与UVM验证实战
  • 大数据学习之SCALA分布式语言三
  • POWER SCHEDULER:一种与批次大小和token数量无关的学习率调度器
  • Mac Electron 应用签名(signature)和公证(notarization)
  • Mybatis初步了解
  • RU 19.26安装(手工安装各个补丁)
  • wxPython中wx.ListCtrl用法(四)
  • 66-《虞美人》
  • 从ai产品推荐到利用cursor快速掌握一个开源项目再到langchain手搓一个Text2Sql agent
  • 4.scala默认参数值
  • YOLO目标检测4
  • C#面试常考随笔6:ArrayList和 List的主要区别?
  • deepseek R1的确不错,特别是深度思考模式
  • excel如何查找一个表的数据在另外一个表是否存在
  • clean code阅读笔记——如何命名?