题目链接:
http://poj.org/problem?id=2891
题目大意: 很好的一道题,解同余式组: x = r1 (mod m1) x = r2 (mod m2) …… x = rp (mod mp)
思路: 因为m1, m2, m3, …… , mp不一定两两互素,所以不能直接用中国剩余定理. 不过,我们可以借用中国剩余定理的思想来解决这道题. 我们一个方程一个方程看, 先看第一个方程x = r1 (mod m1), 则最小的解为r1,满足方程的所有解为:x = r1 + k*m1. 我们现在再加第二个方程:x = r2 (mod m2), 根据上面的解可以变形一下方程:r1 + k*m1 = r2 (mod m2) -> k * m1 = r2 - r1 (mod m2). 则可以根据扩展欧几里德算法求出k(
形如Ax = B (mod C)的同余方程可由扩展欧几里德算法求出,因为它可以转化成ax + by = c的形式~~) 则满足前两个方程的解x就等于r1 + k * m1. 推广一下,如果我们知道了联立前p个方程的解Xp,那么加下一个方程时就可以变为Xp + k * lcm(m1, m2, …… , mp) = r(p+1) (mod m(p+1)),我们依旧可以用扩展欧几里德来求出k,借此求出联立前p+1个方程的解,直到联立完所有解. 无解的判断:当某个方程Xp + k * lcm(m1, m2, …… , mp) = r(p+1) (mod m(p+1))无解时,则整个方程组无解.
/*
①整个过程求解同于方程组
x = a1 (mod m1)
x = a2 (mod m2)
……
x = ar (mod mr)
(m1 m2 …… mr不必互素, (互素直接用中国剩余定理即可) )
②函数indeterminate_equation()求解不定方程ax + by = c -> AX = C (mod B)
*/
#include
#include
using namespace std; void ext_gcd(long long a, long long b, long long &x, long long &y){ if (b == 0){ x = 1; y = 0; return ; } ext_gcd(b, a%b, x, y); long long tmp = x; x = y; y = tmp - a/b * y; return ; } long long gcd(long long a, long long b){ return b ? gcd(b, a % b) : a; } long long lcm(long long a, long long b){ return a / gcd(a, b) * b; } //求解不定方程ax + by = c -> AX = C (mod B) bool indeterminate_equation(long long a, long long b, long long c, long long &x, long long &y){ int g = gcd(a, b); if (c % g != 0){ return false; } a /= g; b /= g; c /= g; ext_gcd(a, b, x, y); x *= c; y *= c; //上面过程是求解出x ,y, 下面过程是求x的最小整数值 long long tmp = abs(double(b)); x = (x % tmp + tmp) % tmp; return true; } long long m[1010]; long long r[1010]; int main(){ int k; while(cin >> k){ long long mlcm = 1; int ok = 1; for (int i = 1; i <= k; i ++){ cin >> m[i] >> r[i]; } long long ans = r[1]; for (int i = 2; i <= k; i ++){ long long a = mlcm = lcm(mlcm, m[i-1]); long long b = m[i]; long long c = r[i] - ans; long long x, y; if (indeterminate_equation(a, b, c, x, y)){ ans = ans + x * mlcm; } else{ cout << -1 << endl; ok = 0; break; } } if (ok) cout << ans << endl; } return 0; }