中國剩余定理


暑假集訓的時候就應該來寫這篇博客的,當時聽的有些糊塗,不過該來的還是得來。。。

中國剩余定理介紹

《孫子算經》中有這樣一個問題:“今有物不知其數,三三數之剩二(除以3余2),五五數之剩三(除以5余3),七七數之剩二(除以7余2),問物幾何?”這個問題稱為“孫子問題”,該問題的一般解法國際上稱為“中國剩余定理”。

在《孫子歌訣》中給出了解決這個問題的解法:三人同行七十稀,五樹梅花廿一支,七子團圓正半月,除百零五便得知。很是朗朗上口,但這是什么意思呢?

具體解法分三步:

找出三個數:

1.從3和5的公倍數中找出被7除余1的最小數15,從3和7的公倍數中找出被5除余1 的最小數21,最后從5和7的公倍數中找出除3余1的最小數70。

2.用15乘以2(2為最終結果除以7的余數),用21乘以3(3為最終結果除以5的余數),同理,用70乘以2(2為最終結果除以3的余數),然后把三個乘積相加(15*2+21*3+70*2)得到和233。

3.用233除以3,5,7三個數的最小公倍數105,得到余數23,即233%105=23。這個余數23就是符合條件的最小數。

就這么簡單。我們在感嘆神奇的同時不禁想知道古人是如何想到這個方法的,有什么基本的數學依據嗎?

中國剩余定理分析

我們將“孫子問題”拆分成幾個簡單的小問題,從零開始,試圖揣測古人是如何推導出這個解法的。

     首先,我們假設n1是滿足除以3余2的一個數,比如2,5,8等等,也就是滿足3*k+2(k>=0)的一個任意數。同樣,我們假設n2是滿足除以5余3的一個數,n3是滿足除以7余2的一個數。

     有了前面的假設,我們先從n1這個角度出發,已知n1滿足除以3余2,能不能使得 n1+n2 的和仍然滿足除以3余2?進而使得n1+n2+n3的和仍然滿足除以3余2?

     這就牽涉到一個最基本數學定理,如果有a%b=c,則有(a+kb)%b=c(k為非零整數),換句話說,如果一個除法運算的余數為c,那么被除數與k倍的除數相加(或相減)的和(差)再與除數相除,余數不變。這個是很好證明的。

     以此定理為依據,如果n2是3的倍數,n1+n2就依然滿足除以3余2。同理,如果n3也是3的倍數,那么n1+n2+n3的和就滿足除以3余2。這是從n1的角度考慮的,再從n2,n3的角度出發,我們可推導出以下三點:

  1. 為使n1+n2+n3的和滿足除以3余2,n2和n3必須是3的倍數。
  2. 為使n1+n2+n3的和滿足除以5余3,n1和n3必須是5的倍數。
  3. 為使n1+n2+n3的和滿足除以7余2,n1和n2必須是7的倍數。

    因此,為使n1+n2+n3的和作為“孫子問題”的一個最終解,需滿足:

  1. n1除以3余2,且是5和7的公倍數。
  2. n2除以5余3,且是3和7的公倍數。
  3. n3除以7余2,且是3和5的公倍數。

    所以,孫子問題解法的本質是從5和7的公倍數中找一個除以3余2的數n1,從3和7的公倍數中找一個除以5余3的數n2,從3和5的公倍數中找一個除以7余2的數n3,再將三個數相加得到解。在求n1,n2,n3時又用了一個小技巧,以n1為例,並非從5和7的公倍數中直接找一個除以3余2的數,而是先找一個除以3余1的數,再乘以2。

    這里又有一個數學公式,如果a%b=c,那么(a*k)%b=a%b+a%b+…+a%b=c+c+…+c=kc(k>0),也就是說,如果一個除法的余數為c,那么被除數的k倍與除數相除的余數為kc。展開式中已證明。

    最后,我們還要清楚一點,n1+n2+n3只是問題的一個解,並不是最小的解。如何得到最小解?我們只需要從中最大限度的減掉3,5,7的公倍數105即可。道理就是前面講過的定理“如果a%b=c,則有(a-kb)%b=c”。所以(n1+n2+n3)%105就是最終的最小解。

 經過分析發現,中國剩余定理的孫子解法並沒有什么高深的技巧,就是以下兩個基本數學定理的靈活運用:

  1. 如果 a%b=c , 則有 (a+kb)%b=c (k為非零整數)。
  2. 如果 a%b=c,那么 (a*k)%b=kc (k為大於零的整數)。

數學分析

用現代數學的語言來說明的話,中國剩余定理給出了以下的一元線性同余方程組:


中國剩余定理說明:假設整數m1m2, ... , mn兩兩互質,則對任意的整數:a1a2, ... , an,方程組(S)有解,並且通解可以用如下方式構造得到:

  1. M = m_1 \times m_2 \times \cdots \times m_n = \prod_{i=1}^n m_i是整數m1m2, ... , mn的乘積,並設M_i = M/m_i, \; \; \forall i \in \{1, 2, \cdots , n\}是除了mi以外的n - 1個整數的乘積。
  2. t_i = M_i^{-1}M_im_i的數論倒數:t_i M_i \equiv 1 \pmod {m_i},  \; \; \forall i \in \{1, 2, \cdots , n\}.
  3. 方程組(S)的通解形式為:x = a_1 t_1 M_1 + a_2 t_2 M_2 + \cdots + a_n t_n M_n + k M= k M + \sum_{i=1}^n a_i t_i M_i, \quad k \in \mathbb{Z}. 在模M的意義下,方程組(S)只有一個解:x = \sum_{i=1}^n a_i t_i M_i.
 1 void exgcd(int a1,int b,int &x,int &y)
 2 {
 3     if(b==0)
 4     {
 5         x=1;
 6         y=0;
 7         return ;
 8     }
 9     exgcd(b,a1%b,x,y);
10     int t=x;
11     x=y;
12     y=t-(a1/b)*y;
13 }
14 int CRT(int a[],int m[],int n)
15 {
16     int M=1,ans=0,t,x,y;
17     for(int i=0; i<n; i++)
18     {
19         M*=m[i];///M為除數乘積
20     }
21     for(int i=0; i<n; i++)
22     {
23         t=M/m[i];///除了mi以外的n-1個整數乘積
24         exgcd(t,m[i],x,y);///求逆元,由擴展歐幾里得轉換成t*ti+m[i]*y=1來求ti
25         ans=(ans+a[i]*x*t)%M;
26     }
27     return (ans+M)%M;
28 }

 

一個正整數K,給出K Mod 一些質數的結果,求符合條件的最小的K。例如,K % 2 = 1, K % 3 = 2, K % 5 = 3。符合條件的最小的K = 23。

Input

第1行:1個數N表示后面輸入的質數及模的數量。(2 <= N <= 10) 
第2 - N + 1行,每行2個數P和M,中間用空格分隔,P是質數,M是K % P的結果。(2 <= P <= 100, 0 <= K < P)Output輸出符合條件的最小的K。數據中所有K均小於10^9。Sample Input

3
2 1
3 2
5 3

Sample Output

23
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define ll long long int
 5 using namespace std;
 6 void exgcd(ll a1,ll b,ll &x,ll &y)
 7 {
 8     ll t;
 9     if(b==0)
10     {
11         x=1;
12         y=0;
13         return ;
14     }
15     exgcd(b,a1%b,x,y);
16     t=x;
17     x=y;
18     y=t-(a1/b)*y;
19 }
20 ll CRT(ll a[],ll m[],ll n)
21 {
22     ll M=1,ans=0,t,x,y,i;
23     for(i=0; i<n; i++)
24     {
25         M*=m[i];
26     }
27     for(i=0; i<n; i++)
28     {
29         t=M/m[i];
30         exgcd(t,m[i],x,y);
31         ans=(ans+a[i]*x*t)%M;
32     }
33     return (ans+M)%M;
34 }
35 
36 int main()
37 {
38     ll n,i,ans;
39     ll a[10],m[10];
40     scanf("%lld",&n);
41     for(i=0;i<n;i++)
42     {
43         scanf("%lld%lld",&m[i],&a[i]);
44     }
45     ans=CRT(a,m,n);
46     printf("%lld\n",ans);
47     return 0;
48 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM