1. 程式人生 > >中國剩餘定理求解同餘線性方程組(模數互素和非互素的情況)

中國剩餘定理求解同餘線性方程組(模數互素和非互素的情況)

中國剩餘定理

     中國剩餘定理是中國古代求解一次同餘方程組的方法,是數論中的一個重要定理。

     設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乘法下的逆元。

中國剩餘定理非互質版

    中國剩餘定理求解同餘方程要求模數兩兩互質,在非互質的時候其實也可以計算,這裡採用的是合併方程的思想。下面是詳細推導。



 

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. int64 Extend_Euclid(int64 a, int64 b, int64&x, int64& y)  
  8. {  
  9.     if(b==0)  
  10.     {  
  11.         x=1,y=0;  
  12.         return a;  
  13.     }  
  14.     int64 d = Extend_Euclid(b,a%b,x,y);  
  15.     int64 t = x;  
  16.     x = y;  
  17.     y = t - a/b*y;  
  18.     return d;  
  19. }  
  20. //求解模線性方程組x=ai(mod ni)  
  21. int64 China_Reminder(int len, int64* a, int64* n)  
  22. {  
  23.     int i;  
  24.     int64 N = 1;  
  25.     int64 result = 0;  
  26.     for(i = 0; i < len; i++)  
  27.         N = N*n[i];  
  28.     for(i = 0; i < len; i++)  
  29.     {  
  30.         int64 m = N/n[i];  
  31.         int64 x,y;  
  32.         Extend_Euclid(m,n[i],x,y);  
  33.         x = (x%n[i]+n[i])%n[i];  
  34.         result = (result + m*a[i]*x%N)%N;  
  35.     }  
  36.     return result;  
  37. }  
  38. int main()  
  39. {  
  40.     int n;  
  41.     while(scanf("%d",&n)!=EOF)  
  42.     {  
  43.         for(int i = 0; i < n; i++)  
  44.             scanf("%I64d %I64d",&a[i],&b[i]);  
  45.         printf("%I64d\n",China_Reminder(n,b,a));  
  46.     }  
  47.     return 0;  
  48. }  
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. int64 gcd(int64 a, int64 b)  
  11. {  
  12.     if(b==0)  
  13.         return a;  
  14.     return gcd(b,a%b);  
  15. }  
  16. int64 Extend_Euclid(int64 a, int64 b, int64&x, int64& y)  
  17. {  
  18.     if(b==0)  
  19.     {  
  20.         x=1,y=0;  
  21.         return a;  
  22.     }  
  23.     int64 d = Extend_Euclid(b,a%b,x,y);  
  24.     int64 t = x;  
  25.     x = y;  
  26.     y = t - a/b*y;  
  27.     return d;  
  28. }  
  29. //a在模n乘法下的逆元,沒有則返回-1  
  30. int64 inv(int64 a, int64 n)  
  31. {  
  32.     int64 x,y;  
  33.     int64 t = Extend_Euclid(a,n,x,y);  
  34.     if(t != 1)  
  35.         return -1;  
  36.     return (x%n+n)%n;  
  37. }  
  38. //將兩個方程合併為一個  
  39. bool merge(int64 a1, int64 n1, int64 a2, int64 n2, int64& a3, int64& n3)  
  40. {  
  41.     int64 d = gcd(n1,n2);  
  42.     int64 c = a2-a1;  
  43.     if(c%d)  
  44.         return false;  
  45.     c = (c%n2+n2)%n2;  
  46.     c /= d;  
  47.     n1 /= d;  
  48.     n2 /= d;  
  49.     c *= inv(n1,n2);  
  50.     c %= n2;  
  51.     c *= n1*d;  
  52.     c += a1;  
  53.     n3 = n1*n2*d;  
  54.     a3 = (c%n3+n3)%n3;  
  55.     return true;  
  56. }  
  57. //求模線性方程組x=ai(mod ni),ni可以不互質  
  58. int64 China_Reminder2(int len, int64* a, int64* n)  
  59. {  
  60.     int64 a1=a[0],n1=n[0];  
  61.     int64 a2,n2;  
  62.     for(int i = 1; i < len; i++)  
  63.     {  
  64.         int64 aa,nn;  
  65.         a2 = a[i],n2=n[i];  
  66.         if(!merge(a1,n1,a2,n2,aa,nn))  
  67.             return -1;  
  68.         a1 = aa;  
  69.         n1 = nn;  
  70.     }  
  71.     Mod = n1;  
  72.     return (a1%n1+n1)%n1;  
  73. }  
  74. int64 a[1000],b[1000];  
  75. int main()  
  76. {  
  77.     int i;  
  78.     int k;  
  79.     while(scanf("%d",&k)!=EOF)  
  80.     {  
  81.         for(i = 0; i < k; i++)  
  82.             scanf("%I64d %I64d",&a[i],&b[i]);  
  83.         printf("%I64d\n",China_Reminder2(k,b,a));  
  84.     }  
  85.     return 0;  
  86. }