中国剩余定理(CRT)
背景
在《孙子算经》中有这样一个问题:“今有物不知其数,三三数之剩二(除以余),五五数之剩三(除以余),七七数之剩二(除以余),问物几何?”这个问题称为“孙子问题”,该问题的一般解法国际上称为“中国剩余定理”。具体解法分三步:
- 找出三个数:从和的公倍数中找出被除余的最小数,从和的公倍数中找出被除余 的最小数,最后从和的公倍数中找出除余的最小数。
- 用乘以(为最终结果除以的余数),用乘以(为最终结果除以的余数),同理,用乘以(为最终结果除以的余数),然后把三个乘积相加得到和。
- 用除以三个数的最小公倍数,得到余数,即。这个余数就是符合条件的最小数。
就这么简单。我们在感叹神奇的同时不禁想知道古人是如何想到这个方法的,有什么基本的数学依据吗?
分析
我们将“孙子问题”拆分成几个简单的小问题,从零开始,试图揣测古人是如何推导出这个解法的。
首先,我们假设是满足除以余的一个数,比如,,等等,也就是满足的一个任意数。同样,我们假设是满足除以余的一个数,是满足除以余的一个数。
有了前面的假设,我们先从这个角度出发,已知满足除以余,能不能使得 的和仍然满足除以余?进而使得的和仍然满足除以余?
这就牵涉到一个最基本数学定理,如果有,则有(为非零整数),换句话说,如果一个除法运算的余数为,那么被除数与倍的除数相加(或相减)的和(差)再与除数相除,余数不变。这个是很好证明的。
以此定理为依据,如果是的倍数,就依然满足除以余。同理,如果也是的倍数,那么的和就满足除以余。这是从的角度考虑的,再从,的角度出发,我们可推导出以下三点:
- 为使的和满足除以余,和必须是的倍数。
- 为使的和满足除以余,和必须是的倍数。
- 为使的和满足除以余,和必须是的倍数。
因此,为使的和作为“孙子问题”的一个最终解,需满足:
- 除以余,且是和的公倍数。
- 除以余,且是和的公倍数。
- 除以余,且是和的公倍数。
所以,孙子问题解法的本质是从和的公倍数中找一个除以余的数,从和的公倍数中找一个除以余的数,从和的公倍数中找一个除以余的数,再将三个数相加得到解。在求,,时又用了一个小技巧,以为例,并非从和的公倍数中直接找一个除以余的数,而是先找一个除以余的数,再乘以。
这里又有一个数学公式,如果,那么 (),也就是说,如果一个除法的余数为,那么被除数的倍与除数相除的余数为。展开式中已证明。
最后,我们还要清楚一点,只是问题的一个解,并不是最小的解。如何得到最小解?我们只需要从中最大限度的减掉掉,,的公倍数即可。道理就是前面讲过的定理“如果,则有”。所以就是最终的最小解。
解法
设正整数两两互素,则同余方程组
有整数解。并且在模下的解是唯一的,解为
其中,而为模的逆元。
Code

int CRT(int a[],int m[],int n) { int M = 1, ans = 0; for(int i = 1; i <= n; i++) M *= m[i]; for(int i = 1; i <= n; i++) { int x, y; int Mi = M/m[i]; exgcd(Mi, m[i], x, y); ans = (ans+Mi*x*a[i])%M; } if(ans<0) ans += M; return ans; }
参考文章:
https://www.cnblogs.com/walker01/archive/2010/01/23/1654880.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)