对于同余方程组:
x=a1 (mod m1); (1)
x=a2 (mod m2); (2)
方程组有一个小于m(m1,m2的最小公倍数)的非负整数解的充分必要条件是(a1-a2)%(m1,m2)==0 ,利用扩展欧几里德算法。
两式联立:a1+m1*y=a2+m2*z。
则:a1-a2=m2*z-m1*y; 这样就可以了解出z和y,则:x=a2+m2*z;
现在我们将其推广到一般情形:(设m1,m2,···,mk两两互素)
x=a1(mod m1);
x=a2(mod m2);
···
x=ak(mod mk);其在M=m1*m2*···*mk;中有唯一整数解。
记Mi=M/mi;因为(Mi,mi)=1,故有两整数pi,qi满足Mi*pi+mi*qi=1,如果记ei=Mi*pi;那么:
ei=0 (mod mj),j!=i;
ei=1(mod mj),j=i;
很明显,e1*a1+e2*a2+···+ek*ak就是方程的一个解,加减M倍后就可以得到最小非负整数解了。
这种情况下 :
a=B[1](mod W[1])
a=B[2](mod W[2])
........
a=B[n](mod W[n])
W[i]与W[j] 互质。
代码为:
__int64 extend_euclid(__int64 a,__int64 b,__int64 &x,__int64
&y)
{
if(b==0)
{
x=1;
y=0;
return
a;
}
__int64 gcd=extend_euclid(b,a%b,x,y);
__int64
temp=x;
x=y;
y=temp-(a/b)*y;
return gcd;
}
int China(int B[],int W[],int k)
{
int i;
int d,x,y,a=0,m,n=1;
for(i=0;i<k;i++)
n*=W[i];
for(i=0;i<k;i++)
{
m=n/W[i];
d=ext_euclid(W[i],m,x,y);
a=(a+y*m*B[i])%n;
}
if(a>0)
return a;
else
return(a+n);
}
如果m1,m2,···,mk不互素,那只能两个两个求了。
x=a1 (mod m1);
x=a2 (mod m2);
解完后,a=x; m=m1和m2的最小公倍数。即可。
分析:
这道题 ai与aj不是互质的,所以只能两个两个的算:
x= b1 (mod a1)
x= b2 (mod a2)
x= b1 + a1*x = b2 +a2*y
code:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace std;
__int64 x,y;
__int64 extended_euclid(int s,int t) //拓展欧拉函数
{
__int64 i,temp;
if(t==0)
{
x=1;
y=0;
return s;
}
else
{
i=extended_euclid(t,s%t);
temp=x;
x=y;
y=temp-(s/t*y);
return i;
}
}
int main()
{
__int64 a1,a2,b1,b2,t,c,n,m,i,j;
while(scanf("%I64d",&t)!=EOF)
{
scanf("%I64d%I64d",&a1,&b1);
int ok=0;
for(i=0;i<t-1;i++)
{
scanf("%I64d%I64d",&a2,&b2);
if(ok) continue;
int e=extended_euclid(a1,a2);
c=b2-b1;
if(c%e)
{
ok=1;
continue;
}
int q=a2/e;
x=(x*c/e%q+q)%q; //求最小的解。。
b1=a1*x+b1; // b=x;
a1=a1*a2/e; // a为a1和a2的最小公倍数。
}
if(ok) printf("-1\n");
else printf("%lld\n",b1);
}
return 0;
}