EXCRT
不保证模数互质
[egin{cases} x equiv b_1 ({
m mod} a_1) \ xequiv b_2 ({
m mod} a_2) \ ... \ x equiv b_n ({
m mod} a_n)end{cases}
]
CRT戳这里
来一手数学归纳法
设已经求出前 (k - 1) 组的一个解 (q)
设 (M = prod_{i = 1}^{k - 1}a_{i})
我们知道前 (k - 1) 组的通解为 (q + xM)
现在考虑第 (k) 组方程
设存在一 (x) 满足
[q + xM equiv b_{k} (mod a_{k})
]
移一下项
[xM equiv b_{k} - q (mod a_{k})
]
于是很愉快的解一下同余方程即可
如此, 我们使用扩展欧几里得算法 (n) 次, 便求出了方程组的解
复杂度 (O(n log n))
P4777 【模板】扩展中国剩余定理(EXCRT)
题目描述
给定 n组非负整数 a_i, b_i 求解关于 x的方程组的最小非负整数解。
Solution
注意中间运算会爆 (longlong) ,使用龟速乘
Code
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<climits>
#define LL long long
#define REP(i, x, y) for(LL i = (x);i <= (y);i++)
using namespace std;
LL RD(){
LL out = 0,flag = 1;char c = getchar();
while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
return flag * out;
}
const LL maxn = 200019;
LL num, a[maxn], b[maxn];
LL x, y;
LL Q_mul(LL a, LL b, LL mod){
LL ans = 0;
while(b){
if(b & 1)ans = (ans + a) % mod;
a = (a + a) % mod;
b >>= 1;
}
return ans % mod;
}
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 temp = x;x = y;y = temp - (a / b) * y;
return d;
}
LL EXCRT(){
LL M = a[1], ans = b[1];
REP(i, 2, num){
LL A = M, B = a[i], C = ((b[i] - ans) % B + B) % B;
LL d = exgcd(A, B, x, y);
if(C % d != 0) return -1;
x = Q_mul(x, C / d, B / d);
ans += x * M;
M *= B / d;
ans = (ans % M + M) % M;
}
return (ans % M + M) % M;
}
int main(){
num = RD();
REP(i, 1, num)a[i] = RD(), b[i] = RD();
printf("%lld
", EXCRT());
return 0;
}