学习笔记:同余
同余
定义
设整数 。若 ,称 为模数(模), 同余于 模 , 是 对模 的剩余。记作 。
否则, 不同余于 模 , 不是 对模 的剩余。记作 。
这样的等式,称为模 的同余式,简称同余式。
根据整除的性质,上述同余式也等价于 。
如果没有特别说明,模数总是正整数。
式中的 是 对模 的剩余,这个概念与余数完全一致。通过限定 的范围,相应的有 对模 的最小非负剩余、绝对最小剩余、最小正剩余。
性质
- 自反性:。
- 对称性:若 ,则 。
- 传递性:若 ,则 。
- 线性运算:若 则有:
- 。
- 。
- 若 , 则 。
- 若 ,则当 成立时,有 。
- 若 ,则当 成立时,有 。
- 若 ,则当 成立时,有 。若 能整除 及 中的一个,则 必定能整除 中的另一个。
应用
扩展欧几里得算法
扩展欧几里得算法(Extended Euclidean algorithm, EXGCD),常用于求 的一组可行解。
过程
设 ,。
由欧几里得定理可知:。
所以 。
又因为 。
所以 ,
。
因为 ,所以 。
将 不断代入递归求解直至 (最大公约数,下同)为 0
递归 x = 1, y = 0
回去求解。
实现
int exgcd(int a, int b, int &x, int &y){
if(b == 0){x = 1;y = 0;return b;}
else{
int d = exgcd(b, a % b, y, x);
y -= a / b * x;return d;
}
}
函数返回的值为 ,在这个过程中计算 即可。
值域分析
的解有无数个,显然其中有的解会爆 long long
。
万幸的是,若 ,扩展欧几里得算法求出的可行解必有 ,下面给出这一性质的证明。
证明:
时,,必在下一层终止递归。
得到 ,显然 。
时,设 。
因为 。
所以 。
。
。
因此 成立。证毕。
中国剩余定理
引入
「物不知数」问题:有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二。问物几何?
即求满足以下条件的整数:除以 余 ,除以 余 ,除以 余 。
该问题最早见于《孙子算经》中,并有该问题的具体解法。宋朝数学家秦九韶于 1247 年《数书九章》卷一、二《大衍类》对「物不知数」问题做出了完整系统的解答。上面具体问题的解答口诀由明朝数学家程大位在《算法统宗》中给出:
三人同行七十希,五树梅花廿一支,七子团圆正半月,除百零五便得知。
,故答案为 。
定义
中国剩余定理 (Chinese Remainder Theorem, CRT) 可求解如下形式的一元线性同余方程组(其中 两两互质):
上面的「物不知数」问题就是一元线性同余方程组的一个实例。
过程
- 计算所有模数的积 ;
- 对于第 个方程:
- 计算 ;
- 计算 在模 意义下的逆元 ;
- 计算 (不要对 取模)。
- 方程组在模 意义下的唯一解为:。
实现
题目描述
自从曹冲搞定了大象以后,曹操就开始捉摸让儿子干些事业,于是派他到中原养猪场养猪,可是曹冲满不高兴,于是在工作中马马虎虎,有一次曹操想知道母猪的数量,于是曹冲想狠狠耍曹操一把。举个例子,假如有 头母猪,如果建了 个猪圈,剩下 头猪就没有地方安家了。如果建造了 个猪圈,但是仍然有 头猪没有地方去,然后如果建造了 个猪圈,还有 头没有地方去。你作为曹总的私人秘书理所当然要将准确的猪数报给曹总,你该怎么办?
输入格式
第一行包含一个整数 —— 建立猪圈的次数,接下来 行,每行两个整数 ,表示建立了 个猪圈,有 头猪没有去处。你可以假定 互质。
输出格式
输出包含一个正整数,即为曹冲至少养母猪的数目。
#include <iostream>
#define int long long
using namespace std;
int n, a[15], b[15];
int p = 1, t = 0;
int exgcd(int a, int b, int &x, int &y){
if(b == 0){x = 1;y = 0;return a;}
else{
int d = exgcd(b, a % b, y, x);
y -= a / b * x;return d;
}
}
int inv(int a, int p){
int x, y;exgcd(a, p, x, y);
return (x % p + p) % p;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin >> n;
for(int i = 1 ; i <= n ; i ++)
cin >> a[i] >> b[i];
for(int i = 1 ; i <= n ; i ++)p *= a[i];
for(int i = 1 ; i <= n ; i ++)
t += (b[i] * p / a[i] * inv(p / a[i], a[i])) % p;
cout << t % p << endl;return 0;
}
证明
我们需要证明上面算法计算所得的 对于任意 满足 。
当 时,有 ,故 。又有 ,所以我们有:
即对于任意 ,上面算法得到的 总是满足 ,即证明了解同余方程组的算法的正确性。
因为我们没有对输入的 作特殊限制,所以任何一组输入 都对应一个解 。
另外,若 ,则总存在 使得 和 在模 下不同余。
故系数列表 与解 之间是一一映射关系,方程组总是有唯一解。
证毕。
解释
下面演示 CRT 如何解「物不知数」问题。
- ;
- 三人同行 七十 希:,故 ;
- 五树梅花 廿一 支:,故 ;
- 七子团圆正 半月:,故 ;
- 所以方程组的唯一解为 。(除 百零五 便得知)
应用
某些计数问题或数论问题出于加长代码、增加难度、或者是一些其他原因,给出的模数:不是质数!
但是对其质因数分解会发现它没有平方因子,也就是该模数是由一些不重复的质数相乘得到。
那么我们可以分别对这些模数进行计算,最后用 CRT 合并答案。
扩展中国剩余定理:模数不互质的情况
两个方程
设两个方程分别是 、;
将它们转化为不定方程:,其中 是整数,则有 。
由裴蜀定理可知,当 不能被 整除时,无解;
其他情况下,可以通过扩展欧几里得算法解出来一组可行解 ;
则原来的两方程组成的模方程组的解为 ,其中 ,。
多个方程
用上面的方法两两合并即可。
题目描述
给定 组非负整数 ,求解关于 的方程组的最小非负整数解。
输入格式
输入第一行包含整数 。
接下来 行,每行两个非负整数 。
输出格式
输出一行,为满足条件的最小非负整数 。
#include <iostream>
#define int __int128
#define MAXN 100005
using namespace std;
int x, y, d, n;
int a, b, A, B;
int read(){
int t = 1, x = 0;char ch = getchar();
while(!isdigit(ch)){if(ch == '-')t = -1;ch = getchar();}
while(isdigit(ch)){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * t;
}
void write(int x){
if(x < 0){putchar('-');x = -x;}
if(x >= 10)write(x / 10);
putchar(x % 10 ^ 48);
}
void exgcd(int a, int b, int &x, int &y){
if(b == 0){d = a;x = 1;y = 0;
}else{
exgcd(b, a % b, y, x);
y -= a / b * x;
}
}
int gcd(int a, int b){return b ? gcd(b, a % b) : a;}
int lcm(int a, int b){return a / gcd(a, b) * b;}
void merge(){
exgcd(a, A, x, y);int c = B - b;
if(c % d){puts("-1");exit(0);}
x = x * c / d % (A / d);
if(x < 0)x += A / d;
int mod = lcm(a, A);
b = (a * x + b) % mod;
if(b < 0)b += mod;
a = mod;
}
signed main(){
n = read();
for(int i = 1 ; i <= n ; i ++){
int _A, _B;
_A = read();_B = read();
A = _A;B = _B;
if(i > 1)merge();
else{a = A;b = B;}
}
write(b % a);putchar('\n');return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现