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就是答案

#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; }