算法证明如上。
在实际求解时,可能不满足n1,n2,n3…nk,互质,那么令N=LCM(n1,n2,…,nk)最小公倍数,即保证算法正确性。
可以发现,求解m时,与a无关,所以,题目若是固定取模的数不动,但是改变a的值,可以预处理出m,然后根据题目计算答案。正是POJ 1006 Biorhythms.
得到的x,可能是正可能负,这只是方程组的一个解,方程组的通解满足X = x + N*t , t为任意整数。
模版:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const int MAXN = 1e5;
/*
x = a1(mod n1)
...
x = ak(mod nk)
x = a1*m1+a2*m2+...+ak*mk
N = LCM(n1, n2, ..., nk)
*/
int num; // 等式的数量
LL a[MAXN];
LL n[MAXN];
LL N; // 调整x的大小时会用到,所以放在全局里
LL LCM(LL* n, int num) {
LL gcd = n[0];
LL ans = 1;
for(int i = 1; i < num; i++)
gcd = __gcd(gcd, n[i]);
for(int i = 0; i < num; i++)
ans *= n[i]/gcd;
return ans;
}
LL exgcd(LL a, LL b, LL& x, LL& y) {
if(b == 0) {
x = 1;
y = 0;
return a;
}else {
LL r = exgcd(b, a%b, x, y);
LL t = y;
y = x-a/b*y;
x = t;
return r;
}
}
LL crt() { // Chinese Remainder Theorem
LL N = LCM(n, num);
LL x = 0;
for(int i = 0; i < num; i++) {
LL u, v;
exgcd(n[i], N/n[i], u, v);
// mi = N/n[i]*v;
x += N/n[i]*v*a[i];
}
return x;
}
int main() {
scanf("%d", &num);
for(int i = 0; i < num; i++) {
scanf("%lld%lld", &a[i], &n[i]);
}
LL x = crt(); // 计算等式一个解
cout << x << endl;
return 0;
}