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;

}

你可能感兴趣的:(Integer)