【学习笔记】中国剩余定理
声明:本博客所有随笔都参照了网络资料或其他博客,仅为博主想加深理解而写,如有疑问欢迎与博主讨论✧。٩(ˊᗜˋ)و✧*。
前言
找了一些博客,好像都是直接给你结论然后再分析,顺序让我有点难接受,打算按自己的思路理一遍
这篇博客写的好棒!!
————————————————————————————٩(ˊᗜˋ)و✧*————————————————————————————
一、概念
给定 \(n\) 组非负整数 \(a_i\), \(b_i\),求解关于 \(x\) 的方程组的最小非负整数解。
保证 \(b_i\),\(b_j\) 互质
————————————————————————————٩(ˊᗜˋ)و✧*————————————————————————————
二、分析
方程有点多,我们先从一个方程解起
对于方程 \(x_i\equiv b_i(\bmod a_i)\) ,很显然 \(x_i = a_i + b_i * k \ ( \ k \in Z \ )\)
那么对于 \(n\) 个方程就有 \(n\) 个 \(x\),我们想想能否将它们合并?
例如,对于 \(s = x_i + x_j\),我们想要 \(s\) 仍然满足 \(s\equiv b_i(\bmod a_i)\),\(s\equiv b_j(\bmod a_j)\)
显然,\(( \ x_i + k * b_i \ ) \ \% \ b_i = a_i\),所以只要 \(x_j\) 为 \(b_i\) 的倍数即可,同样,\(x_i\) 也得为 \(b_j\) 的倍数
把它推广一下,即当 \(s = x_1 + x_2 + x_3 + ... + x_n\) 时,为满足 \(s \ \% \ b_i = a_i\),则 \(x_1,x_2...x_{i-1},x_{i+1}...x_n\) 得为 \(b_i\) 的倍数
整理一下可得,所有的 \(x_i\) 得为 \(b_j \ ( \ j \neq i \ )\) 的倍数,同时 \(x_i \ \% \ b_i = a_i\)
还有一个小技巧就是,找 \(x_i\) 的时候可以先找 \(\prod\limits_{j \neq i}a_j\) 在 \(b_i\) 下的逆元(这里要用扩展欧几里得),再乘以 \(a_i\)
————————————————————————————٩(ˊᗜˋ)و✧*————————————————————————————
三、结论
————————————————————————————٩(ˊᗜˋ)و✧*————————————————————————————
四、\(Code\)
#include<bits/stdc++.h>
#define F(i, x, y) for(int i = x; i <= y; ++ i)
#define ll long long
using namespace std;
ll read();
const int N = 15;
int n;
ll a[N], b[N];
ll mod = 1, ans, x, y;
int exgcd(ll a, ll b, ll &x, ll &y)
{
if(b == 0)
{
x = 1, y = 0;
return a;
}
int r = exgcd(b, a % b, x, y), tmp = y;
y = x - a / b * y, x = tmp;
return r;
}
int main()
{
n = read();
F(i, 1, n) b[i] = read(), a[i] = read(), mod *= b[i];
F(i, 1, n)
{
exgcd(mod / b[i], b[i], x, y);
ans = ((ans + a[i] * x * (mod / b[i])) % mod + mod) % mod;
}
printf("%lld\n", ans % mod);
}
ll read()
{
ll x = 0;
char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x;
}