中国剩余定理求解同余线性方程组(模数互素和非互素的情况)

参考:http://yzmduncan.iteye.com/blog/1323599

中国剩余定理

     中国剩余定理是中国古代求解一次同余方程组的方法,是数论中的一个重要定理。

     设m1,m2,m3,…,mk是两两互素的正整数,即gcd(mi,mj)=1,i!=j,i,j=1,2,3,…,k.

则同余方程组:

x = a1 (mod n1)

x = a2 (mod n2)

x = ak (mod nk)

模[n1,n2,…nk]有唯一解,即在[n1,n2,…,nk]的意义下,存在唯一的x,满足:

x = ai mod [n1,n2,…,nk], i=1,2,3,…,k。

解可以写为这种形式:

x = sigma(ai* mi*mi’) mod(N)

      其中N=n1*n2*…*nk,mi=N/ni,mi’为mi在模ni乘法下的逆元。

 

中国剩余定理非互质版

    中国剩余定理求解同余方程要求模数两两互质,在非互质的时候其实也可以计算,这里采用的是合并方程的思想。下面是详细推导。


《中国剩余定理求解同余线性方程组(模数互素和非互素的情况)》
 

FZU1402 中国剩余定理

Cpp代码  

  1. #include <iostream>  
  2. #include <cstdio>  
  3. #include <cstring>  
  4. using namespace std;  
  5. typedef __int64 int64;  
  6. int64 a[15],b[15];  
  7.   
  8. int64 Extend_Euclid(int64 a, int64 b, int64&x, int64& y)  
  9. {  
  10.     if(b==0)  
  11.     {  
  12.         x=1,y=0;  
  13.         return a;  
  14.     }  
  15.     int64 d = Extend_Euclid(b,a%b,x,y);  
  16.     int64 t = x;  
  17.     x = y;  
  18.     y = t – a/b*y;  
  19.     return d;  
  20. }  
  21. //求解模线性方程组x=ai(mod ni)  
  22. int64 China_Reminder(int len, int64* a, int64* n)  
  23. {  
  24.     int i;  
  25.     int64 N = 1;  
  26.     int64 result = 0;  
  27.     for(i = 0; i < len; i++)  
  28.         N = N*n[i];  
  29.     for(i = 0; i < len; i++)  
  30.     {  
  31.         int64 m = N/n[i];  
  32.         int64 x,y;  
  33.         Extend_Euclid(m,n[i],x,y);  
  34.         x = (x%n[i]+n[i])%n[i];  
  35.         result = (result + m*a[i]*x%N)%N;  
  36.     }  
  37.     return result;  
  38. }  
  39.   
  40. int main()  
  41. {  
  42.     int n;  
  43.     while(scanf(“%d”,&n)!=EOF)  
  44.     {  
  45.         for(int i = 0; i < n; i++)  
  46.             scanf(“%I64d %I64d”,&a[i],&b[i]);  
  47.         printf(“%I64d\n”,China_Reminder(n,b,a));  
  48.     }  
  49.     return 0;  
  50. }  

 

 

 

POJ2891 非互质版

Cpp代码  

  1. /** 
  2. 中国剩余定理(不互质) 
  3. */  
  4. #include <iostream>  
  5. #include <cstdio>  
  6. #include <cstring>  
  7. using namespace std;  
  8. typedef __int64 int64;  
  9. int64 Mod;  
  10.   
  11. int64 gcd(int64 a, int64 b)  
  12. {  
  13.     if(b==0)  
  14.         return a;  
  15.     return gcd(b,a%b);  
  16. }  
  17.   
  18. int64 Extend_Euclid(int64 a, int64 b, int64&x, int64& y)  
  19. {  
  20.     if(b==0)  
  21.     {  
  22.         x=1,y=0;  
  23.         return a;  
  24.     }  
  25.     int64 d = Extend_Euclid(b,a%b,x,y);  
  26.     int64 t = x;  
  27.     x = y;  
  28.     y = t – a/b*y;  
  29.     return d;  
  30. }  
  31.   
  32. //a在模n乘法下的逆元,没有则返回-1  
  33. int64 inv(int64 a, int64 n)  
  34. {  
  35.     int64 x,y;  
  36.     int64 t = Extend_Euclid(a,n,x,y);  
  37.     if(t != 1)  
  38.         return -1;  
  39.     return (x%n+n)%n;  
  40. }  
  41.   
  42. //将两个方程合并为一个  
  43. bool merge(int64 a1, int64 n1, int64 a2, int64 n2, int64& a3, int64& n3)  
  44. {  
  45.     int64 d = gcd(n1,n2);  
  46.     int64 c = a2-a1;  
  47.     if(c%d)  
  48.         return false;  
  49.     c = (c%n2+n2)%n2;  
  50.     c /= d;  
  51.     n1 /= d;  
  52.     n2 /= d;  
  53.     c *= inv(n1,n2);  
  54.     c %= n2;  
  55.     c *= n1*d;  
  56.     c += a1;  
  57.     n3 = n1*n2*d;  
  58.     a3 = (c%n3+n3)%n3;  
  59.     return true;  
  60. }  
  61.   
  62. //求模线性方程组x=ai(mod ni),ni可以不互质  
  63. int64 China_Reminder2(int len, int64* a, int64* n)  
  64. {  
  65.     int64 a1=a[0],n1=n[0];  
  66.     int64 a2,n2;  
  67.     for(int i = 1; i < len; i++)  
  68.     {  
  69.         int64 aa,nn;  
  70.         a2 = a[i],n2=n[i];  
  71.         if(!merge(a1,n1,a2,n2,aa,nn))  
  72.             return -1;  
  73.         a1 = aa;  
  74.         n1 = nn;  
  75.     }  
  76.     Mod = n1;  
  77.     return (a1%n1+n1)%n1;  
  78. }  
  79. int64 a[1000],b[1000];  
  80. int main()  
  81. {  
  82.     int i;  
  83.     int k;  
  84.     while(scanf(“%d”,&k)!=EOF)  
  85.     {  
  86.         for(i = 0; i < k; i++)  
  87.             scanf(“%I64d %I64d”,&a[i],&b[i]);  
  88.         printf(“%I64d\n”,China_Reminder2(k,b,a));  
  89.     }  
  90.     return 0;  
  91. }  
点赞