中國剩余定理
有物不知其數,三三數之剩二,五五數之剩三,七七數之剩二。問物幾何?即,一個整數除以三余二,除以五余三,除以七余二,求這個整數。
《孫子算經》中首次提到了同余方程組問題,以及以上具體問題的解法,因此在中文數學文獻中也會將中國剩余定理稱為孫子定理。
換句話說:“一個正整數除以3余2,除於5余3,除於7余2,求這個正整數是幾?”
基本解法:
1)先找到除以3余2,除於7余2的數是那些。經過分析得到滿足要求的數是21的倍數加2。
2,23,44,65,96,107,........
2)在上述結果中繼續尋找除以5余3的數。
3)滿足上述要求的正整數是:23,128,233,338
這里 128-23=105 正好是[3,5,7]的最小公倍數
古人的解法:
先找5和7的公倍數中除以3余1的數:70
再找3和7的公倍數中除以5余1的數:21
再找3和5的公倍數中除以7余1的數:15
70*2+21*3+15*2=233
233-105=128
128-105=23
所以這個正整數最小是23.
先考慮問題的分解:
問題1:計算一個整數
,使得它滿足除以3余2、除以5余3、除以7余2。
如果能夠找到三個整數
,使得:
除以3余2、除以5余0、除以7余0;
除以3余0、除以5余3、除以7余0;
除以3余0、除以5余0、除以7余2;
那么令
,就很容易驗證這時的
就滿足除以3余2、除以5余3、除以7余2。
分別稱找到整數
的問題為問題1-1、問題1-2、問題1-3。可以看出這三個問題本質上是類似的。
普通的中國剩余定理要求所有的
互素,那么如果不互素呢,怎么求解同余方程組?
這種情況就采用兩兩合並的思想,假設要合並如下兩個方程:

那么得到:

我們需要求出一個最小的xx使它滿足:

那么x1x1和x2x2就要盡可能的小,於是我們用擴展歐幾里得算法求出x1x1的最小正整數解,將它代回a1+m1x1,得到x的一個特解x′,當然也是最小正整數解。
所以xx的通解一定是x′加上lcm(m1,m2)∗k,這樣才能保證x模m1和m2的余數是a1和a2。由此,我們把這個x′x′當做新的方程的余數,把lcm(m1,m2)當做新的方程的模數。(這一段是關鍵)
合並完成:

代碼:
#include<bits/stdc++.h>
using namespace std; int const MAXN=10010; int x,y; int k;//k組同余方程
int a[MAXN];//每個同余方程的余數
int b[MAXN];//每個同余方程的模數
int ans; int lcm=1; void exgcd(int a,int b) { if(b==0){x=1;y=0;} else{ exgcd(b,a%b); int tmp=x; x=y; y=tmp-a/b*y; } return; } int main() { cin>>k; for(int i=1;i<=k;++i) cin>>b[i]>>a[i]; for(int i=1;i<=k;++i) lcm*=b[i]; for(int i=1;i<=k;++i) { exgcd(lcm/b[i],b[i]); x=(x%b[i]+b[i])%b[i]; ans=(ans+(lcm/b[i])*x*a[i])%lcm; } cout<<ans; }
