1. 程式人生 > >中國剩余定理(孫子定理)詳解 (轉)

中國剩余定理(孫子定理)詳解 (轉)

col == 了解 turn 情況下 歐幾裏得算法 得到 輾轉相除法 人的

原文:https://www.cnblogs.com/freinds/p/6388992.html

問題:今有物不知其數,三三數之剩二,五五數之剩三,七七數之剩二。問物幾何?

說明白一點就是說,存在一個數x,除以3余2,除以5余三,除以7余二,然後求這個數。上面給出了解法。再明白這個解法的原理之前,需要先知道一下兩個定理。

定理1:幾個數相加,如果存在一個加數,不能被數a整除,那麽它們的和,就不能被整數a整除。

定理2:兩數不能整除,若除數擴大(或縮小)了幾倍,而被除數不變,則其商和余數也同時擴大(或縮小)相同的倍數(余數必小於除數)。

這兩個定理淺顯易懂,自己找個例子就能理解,就不再贅述了。

現給出求解該問題的具體步驟:

1、求出最小公倍數

lcm=3*5*7=105

2求各個數所對應的基礎數

(1)105÷3=35

35÷3=11......2 //基礎數35

(2)105÷5=21

21÷5=4......1

定理2把1擴大3倍得到3,那麽被除數也擴大3倍,得到21*3=63//基礎數63

3105÷7=15

15÷7=2......1

定理2把1擴大2倍得到2,那麽被除數也擴大2倍,得到15*2=30//基礎數30

把得到的基礎數加和(註意:基礎數不一定就是正數)

35+63+30=128

4減去最小公倍數lcm(在比最小公倍數大的情況下)

x=128-105=23

那麽滿足題意得最小的數就是23了。一共有四個步驟。下面詳細解釋每一步的原因。

(1)最小公倍數就不用解釋了,跳過(記住,這裏討論的都是兩兩互質的情況)

(2)觀察求每個數對應的基礎數時候的步驟,比如第一個。105÷3=35。顯然這個35是除了當前這個數不能整除以外都能夠被其他數整除,就是其他數的最小公倍數。相當於找到了最小的開始值,用它去除以3發現正好余2。那麽這個基礎數就是35。記住35的特征,可以整除其他數但是不能被3整除,並且余數是2。體現的還不夠明顯,再看下5對應的基礎數。21是其他數的最小公倍數,但是不能被5整除,用21除以5得到的余數是1,而要求的數除以5應該是余1的。所以余數被擴大,就得到了相應的基礎數63。記住這個數的特征,可以被其他數整除但是被5除應該余三。同理,我們得到了第三個基礎數23,那麽他的特征就是:可以被其他數整除,但是不能被7整除,並且余數為2。

(3)第三步基礎數加和,為什麽要這樣做呢?利用就是上面提到的定理1。

35+63+30=128。對於3來說,可以把63+30的和看作一個整體,應該他們都可以被3整除。看著上面寫出的三個數的特征,運用定理1來說,就是在35的基礎上加上一個可以被3整除的倍數,那麽得到的結果依然還是滿足原先的性質的,就是128除以同樣還是余2的。同理,對於5還說,這個數被除之後會剩余3;對於7來說,被除之後剩余2。所以說,我們當前得到的這個數是滿足題目要求的一個數。但是這個數是不是最小的,那就不一定了。

(4)應該不能確定是不是最小的數,這個時候就要用到他們的最小公倍數了。最小公倍數顧名思義,一定是一個同時被幾個數整除的最小的一個數,所以減去它剩余下來的余數還是符合題意要求的。當然也同樣可以運用定理1來解釋,只不過是加法變成了減法,道理還是一樣的。當然具體要不要剪還是要看和lcm的大小關系的。

稍微的總結一下:就是已知m1,m2,m3是兩兩互質的正整數,求最小的正整數x,使它被m1,m2,m3除所得的余數分別是c1,c2,c3。孫子定理的思想便是線分別求出被其中數mi整除余1而被兩外兩個數整除的數Mi(i=1,2,3),則所求數之一的便是c1M1+c2M2+c3M3。由此我們可以得到n個兩兩互質數的情況。證明上面已經一步一步給出。

那麽,到此為止基本的中國剩余定理的內容我們以及了解了,包括解答方法。那麽如何編碼呢?按照上面這個思路去編碼,其實並不難。一共分為四大步。但是,大多數人的困惑在於如何求取基礎數。這裏呢,提供兩種方法:

(1)第一種就是一直遞增,直到找到。例如:3的基礎數,35是其他數的最小公倍數。那麽就從35開始,一直自增,知道余數為2,便停止(利用while循環)。

(2)第二種方法呢就是輾轉相除法上得來的。這裏的例子體現的不夠明顯,應當看看去求取乘法逆元的過程,下面講的內容和乘法逆元有很大的關系,所以還是看看的好。簡單舉個例子:

假設現在三個數分別是14,3,5,它們兩兩互質,且要求的數除以5余3。求5對應的基礎數。有:

42÷5=8......2

5÷2=2......1

所以1=5-2*2=5-2*(42-8*5)=-2*42+17*5

那麽-2*42=-84 17*5=85 -84+85=1

把1擴大3倍變成3,則有-84*3=-252也就是5對應的基礎數。

第一點: 基礎數可以是負數,這個之前點到過。//並且下面的解法就是有這樣的。

第二點: 當得到余數為1的時候後面的算式相當於是一個回溯的過程,最後解到-2*42。 但是還只不過是余數是1的情況對應的數,再運用定理2我們就得到了-252這個基礎數。實際上要是看過乘法逆元,這裏實際就是乘法逆元的求解過程,而-2也就是42關於15取模的乘法逆元。

模板:

 1 /*long long gcd(LL a,LL b)
 2 {
 3     return b==0?a:gcd(b,a%b);
 4 }*/
 5 #include<cstdio>
 6 #define ll long long
 7 //擴展歐幾裏得算法 
 8 void gcd(ll a,ll b,ll &d,ll &x,ll &y)
 9 {
10     if(b==0){
11         d=a;
12         x=1,y=0;
13     }
14     else{//else不能省略 
15         gcd(b,a%b,d,y,x);
16         y-=(a/b)*x;
17     }
18 }
19 //中國剩余定理 
20 ll China(int n,ll *m,ll *a)
21 {
22     ll M=1,d,y,x=0;
23     for(int i=0;i<n;i++) M*=m[i];
24     for(int i=0;i<n;i++){
25         ll w=M/m[i];
26         gcd(m[i],w,d,d,y);
27         x=(x+y*w*a[i])%M;
28     }
29     return (x+M)%M;
30 }
31 ll m[15],a[15];
32 int main()
33 {
34     int n;
35     scanf("%d",&n);
36     for(int i=0;i<n;i++)
37         scanf("%lld%lld",&m[i],&a[i]);
38     printf("%lld",China(n,m,a));
39 }

中國剩余定理(孫子定理)詳解 (轉)