poj 2891 Strange Way to Express Integers

由于bi,bj不保证互素,不能用直接套中国剩余定理,做法是利用欧几里德扩展定理,将两个等式合并,然后再与其他的等式一一合并

 对于x=b1 mod a1,x= b2 mod a2,设x=b1+m1*a1 , x = b2 + m2*a2;所以 b1 +m1*a1 = b2 + m2*a2;

所以a1*m1=b1-b2 mod a2,利用欧几里德扩展定理求出最小的非负m1,那么x=b1+m*a1就已知,且x最小,如果无解,整个同余式组无解;

 同时,x+k*a1是所有满足x≡b1 mod a1的解,而x+k'*a2又是所有满足x≡b2 mod a2的解

那么,将x+k*b1与x+k'*b2合并,得到的式子就是x+k*lcm(b1,b2)

于是,上面两个式子可以用x'=x mod lcm(b1,b2)来替代

最后,就只剩下一个式子了,求得的最小的x就是答案

View Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<cstring>
#include<vector>
#define LL long long
using namespace std;
LL Ex_Gcd( LL a, LL b , LL &x , LL &y )
{
      if( b == 0 ) 
      {
          x = 1;  y = 0;
          return a;
      }    
      LL mod = Ex_Gcd( b , a%b , x , y );
      LL temp = x;
      x = y;
      y = temp - ( a / b )*y;
      return mod;
} 
int main(  )
{
    int n;
    LL x,y,a1,b1,a2,b2;
    while( scanf( "%d",&n )==1 )
    {
           bool flag = false;
           scanf( "%I64d %I64d",&a1,&b1 );
           for( int i = 1; i < n ; i ++ )
           {
                scanf( "%I64d %I64d",&a2,&b2 );
                if( flag ) continue;
                LL mod = Ex_Gcd( a1 , a2 , x ,y );
                LL  c = b2 - b1;
                if( c % mod  )
                {
                    flag = true;
                    continue;
                }
                LL  p = a2/mod;
                x = ( (x*c/mod)%p + p )%p;
                b1 = a1*x + b1;
                a1 = a1*a2/mod;
           }
           if( flag )  puts( "-1" );
           else printf( "%I64d\n",b1 );    
    }
    //system( "pause" );
    return 0;
}
posted @ 2012-07-20 21:32  wutaoKeen  阅读(140)  评论(0)    收藏  举报