您的位置:首页 > 其它

POJ 2891 Strange Way to Express Integers ★ (扩展欧几里德解同余式组)

2013-01-06 23:44 465 查看
题目链接: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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: