题目大意:求解同余方程组,不保证模数两两互质。
如果模数互质的话,那么我们可以用CRT求解,要是不互质呢?我们就没办法了吗?当然不是。我们可以用exgcd将方程合并来求解。
首先我们先以两个方程为例:
A ≡ r1 (mod a1)
A ≡ r2 (mod a2)
我们把这两个方程写成这样的形式:A = r1 - x * a1,A = r2 + y * a2.
两式相减一下,得到:x * a1 + y * a2 = r1 - r2.
这就是一个不定方程的形式。它有解的条件是 (a1,a2) | r1 - r2,否则这个方程无解,那么整个同余方程组也无解。
如果有解的话,那么我们可以先用exgcd求出不定方程的特解x,把它乘以(r1-r2)/(a1,a2),这样的话我们就得到了最小正整数解x,把它带回到第一个同余方程里,那么我们就知道了一个A的特解A0。
之后,又因为A的解必然与A0关于[a1,a2]同余(这个是定理),那么我们就得到了一个新的同余方程:A≡A0 (mod [a1,a2])
我们就把两个方程合并为一个方程,之后继续合并即可得解,注意合并过程中任意一次出现无解的情况那么整个方程即无解。
看一下代码。
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<iostream> #include<queue> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar(' ') using namespace std; typedef long long ll; const int M = 1000005; int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { ans *= 10; ans += ch - '0'; ch = getchar(); } return ans * op; } ll n,r[M],a[M],x,y; ll exgcd(ll a,ll b,ll &x,ll &y) { if(!b) { x = 1,y = 0; return a; } ll d = exgcd(b,a%b,y,x); y -= a / b * x; return d; } ll solve() { ll M = a[1],R = r[1]; rep(i,2,n) { ll d = exgcd(M,a[i],x,y); if((R - r[i]) % d) return -1; x = (R - r[i]) / d * x % a[i];//x是本次解得的一组特解 R -= x * M;//R是现在的余数,也就是A0 M = M / d * a[i];//M是新的模数,也就是[a1,a2] R %= M; } R = (R+M) % M; return R; } int main() { while(scanf("%lld",&n) != EOF) { rep(i,1,n) a[i] = read(),r[i] = read(); printf("%lld ",solve()); } return 0; }