poj 2891(中国剩余定理 ------迭代法来求解)

这个题不能直接应用中国剩余定理,因为m的值可能不互素。。。。所以用两两求解的方法来求解(应该是叫迭代吧。。。自己是这么跟别人说的。。。)看下面的例子。。

x = 1 (mod 5)

x = 2 (mod 6)

x = 3 (mod 7)

首先我们把第一个方程写成 x =   5*t+1 ,然后带入第二个方程,得5*t + 1 = 2(mod 6)    ==>  t = 5(mod 6) ;再写成 t = 6*u+5 

则 x = 5*(6*u+5)+1 = 30 *u +26; 再次带入第三个方程,30 *u +26=3(mod 7) 可以得出 u=6(mod 7);

则 u = 7*v+6 ; x = 30*(7*v + 6)+26=210*v+206; 

所以 x = 206(mod 207);

就按照这样不断更新 a*x=b(mod n) 中的a 和 n ,逐次带入来求解。。。。。


#include <iostream>
using namespace std;
#define LL long long
LL ex_gcd(LL a, LL b, LL &x, LL &y) {
    if (b == 0) {
        x = 1, y = 0;
        return a;
    }
    LL d = ex_gcd(b, a % b, x, y);
    LL t = x;
    x = y;
    y = t - a / b*y;
    return d;
}
LL mod(LL a,LL b,LL n,LL &d){ // a*x=b(mod n) ,d 是返回a, n的最大公约数
    LL e,x,y;
    d=ex_gcd(a,n,x,y);
    if(b%d!=0) return -1;
    e=(x*(b/d))%n;
    while(e<0) e+=n/d; // a,n 可能不互素 所以加n/d 可以得到最小正整数解
    return e;
}
int main(int argc, char** argv) {
    bool flag;
    LL m,a1,m1,a2,m2,x,d;
    while(scanf("%lld",&m)!=-1){
        scanf("%lld%lld",&m1,&a1);
        flag=0;
        for(int i=1;i<m;i++){
            scanf("%lld%lld",&m2,&a2);
            if(flag) continue;
            x=mod(m1,a2-a1,m2,d);
            if(x==-1){
                flag=1; continue;
            }
            a1+=m1*x;
            m1=m1*m2/d;
            a1=(a1%m1+m1)%m1;
        }
        if(flag)
            printf("-1\n");
        else
            printf("%lld\n",a1);
    }
    return 0;
}


你可能感兴趣的:(poj 2891(中国剩余定理 ------迭代法来求解))