poj2891 中国剩余定理

本文介绍如何解决同余方程组问题,包括当模数互素时使用中国剩余定理求解的方法,以及模数不互素时的解决策略。通过扩展欧几里德算法来寻找解,并提供了具体的实现代码。

对于同余方程组:

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值