【数论】——同余
定义
- 若存在整数 a.b,除以 m 的余数相同,则称 a,b mod m 同余,记为:
同余系 & 剩余系
- 同余系:对区间 [1,m-1], 集合 {a+km} 的所有数 mod m,余数都是 a,称集合为一个 mod m 的同余类,记做:。
- 剩余系:mod m 的同余类有 m 个:
构成 m 的完全剩余系; [1,m] 中与 m 互质的数代表的同余类有: 个,构成 m 的简化剩余系。
- 简化剩余系关于 mod m 乘法封闭: 任取其中 a,b 与 m 互质,则 a*b 也与 m 互质(反证法证明)。
扩展欧几里得
- 对于任意整数 a,b,存在一对整数 x,y,有:
证明
- 若 b = 0,则当:
公式成立。
- 若 b>0, 根据欧几里得算法:
此时不妨假设存在: 使得
对 展开有:
代入有:
分理出 x,y:
令,, 代入上式:
通过以上方式,可以运用数学归纳法,得证扩展欧几里得。
代码实现
- 在欧几里得的基础上,传入 x,y,运用: 即可递推得的到系数 x,y。
- 代码
int extend_gcd(int a, int b, int& x, int& y)// 函数返回 a,最大公约数
{
if (!b) {
x = 1, y = 0;
return a;
}
int d = gcd(b, a % b, x, y);
int t = x;// 临时记录 x
// 利用:x'= y,y' = x-[a/b]*y
x = y;
y = t - y * (a / b);
return d;
}
线性同余方程
定义
- 对于整数 a,b,m,满足:
求整数 x(有解或无解)。由于未知数最高次为 1,因此又被称为一次同余方程。
求解
- 由定义式易知: 是 m 的倍数,不妨设商为 对定义式去模运算:
则原方程的解等价于求满足上式的 x 的值。
- 方程有解等价于:
- 因此可以借助扩展欧几里得进行求解
代码
int solve(int a, int m, int& x, int& y)
{if (!m) {
x = 1, y = 0;
return a;
}
int d = solve(m, a % m, x, y);
int t = x;
y = x;
x = t - (a / m) * y;
return d;
}
bool check(int m,int d)
{return m % d == 0;}
void answer(int a,int m)
{
int x, y;
int d = solve(a, m, x, y);
int answer;
if (check(m, d))
answer = (x % m + m) % m;
else
puts("impossible");
}
线性同余方程组
定义
- 对于 n 对模数与被模数 , 有:
求解
- 中国剩余定理 设 为
若 之间两两互质,设 为:()
解 为:
- 证明——(来自 李煜东 《算法竞赛进阶指南》)
- m 不满足互余下的通解
- 取出前两个式子:
去模处理:
联立并化简:
根据扩展欧几里得, 求解 不定方程 的解为:
化简:
令
因此方程组中所有式子两两合并,n-1 次后最终可以化为一个形如 的等式。 最终求解:
中 x 的解,等价于:的最小正整数。
代码
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, x, y);
LL t = x;
x = y;
y = t - (a / b) * y;
return d;
}
LL mod(LL a, LL b)
{
return ((a % b) + b) % b;
}
int main()
{
int n;
scanf("%d", &n);
LL a, m;
bool flag = true;
scanf("%lld%lld", &a, &m);//先读入第一个式子
n--;
//读入剩余的并合并
while (n--) {
LL a0, m0;
scanf("%lld%lld", &a0, &m0);
LL k1, k2;
LL d = exgcd(a, -a0, k1, k2);
if ((m0 - m) % d) {//如果同余方程无解
flag = false;
break;
}
k1 = mod(k1 * (m0 - m) / d, abs(a0 / d));//防止溢出
m = a * k1 + m;//合并后的m = a*k1+m
a = abs(a / d * a0);//合并后的a = lcm(a,a0)
}
if (flag)
printf("%lld", mod(m, a));
else
puts("-1");
return 0;
}