今有物不知其數,三三數之余二;五五數之余三;七七數之余二。問物幾何?
語文水平不高,大概翻譯一下:
今天Rothen釣了幾個妹子,3個3個的數會余下2個,5個5個的數會余下3個,七個七個的數會剩下2個
好吧,這樣好像更難理解了,懶得翻譯了,反正大家都看得懂,大佬們就先做會吧,反正對於您這種神犇那肯定是秒切啊!。
中國剩余定理???好高級的東西啊,嚇得我趕緊來個BFS( Baidu First Search)
發現中國剩余定理又叫孫子定理,原因是孫子發明的(這名字絕了)
然后對於上面的題目的解法為:
(注意,中國剩余定理的解法只能用於幾個模數兩兩互質的情況)
1.首先找出5和7的 mod 3等於1的公倍數(70),然后找出3和7的mod 5 等於1的公倍數(21),還有就是3 和 5的mod 7等於1的公倍數(15)
2.答案就是上面求出來的三個數的乘積分別乘以"對應的余數" mod 所有模數的乘積 例如 (70*2+21*3+15*2)mod (7*3*5)得到23
納尼!這么神奇的嗎?
真的就是這么神奇哦~
本蒟蒻查閱對於這個定理的證明為:
把上面的問題轉化為多個個子問題:
假設存在一個數x1 % 3 =2("%"就是取余數),那么x1就能表示為3k+2的形式(k >= 0)
假設存在一個數x2 % 5 =3("%"就是取余數),那么x1就能表示為5k+3的形式(k >= 0)
假設存在一個數x3 % 7 =2("%"就是取余數),那么x1就能表示為7k+2的形式(k >= 0)
那么考慮如果存在一個
x1 + x2 + x3使得它們滿足上面的所有條件呢?
首先有個特別基礎的公式:A % B = C, 那么(A + B*K) % B =C
這個應該很好理解,你可以這么想:跟上面的類似,A可以表示為 若干倍的B加上C,
而A+B*k就可以表示為:若干倍的B + C +K倍的B ,自然的對於(A+B*k)%B也是等於C了啊!
回到剛才的問題,怎么樣才能使得x1+x2+x3滿足條件呢?
若要使得(x1+x2+x3)%3仍然余下2,那么x2,x3就一定要是三的倍數
若要使得(x1+x2+x3)%5仍然余下3,那么x1,x3就一定要是五的倍數
若要使得(x1+x2+x3)%7仍然余下2,那么x1,x2就一定要是七的倍數
所以問題就轉化為了求出x1,x2,x3
哦吼,從上面我們看出了x1,x2,x3的幾個性質:
1.x1是5和7的公倍數,而且x1 % 3 = 2
2.x2是3和7的公倍數,而且x2 % 5 = 3
3.x3是3和5的公倍數,而且x3 % 7 = 2
同時又引入一個數學公式:
如果a%b=c,那么(a*k)%b=(a%b+a%b+a%b+...+a%b(k個a%b) ) mod b=c×k mod b
然后問題就可以用開篇的方法解決了呀!而且找出來的是最小滿足條件的數。
妙啊!
例題:
P1495 【模板】中國剩余定理(CRT)/曹沖養豬
板子,不多贅述。
放上我這丑的一批的代碼:
#include <bits/stdc++.h> #define int long long using namespace std; int n,a[15],b[15],c[15],q=1,sum=0; signed main(){ cin>>n; for (int i = 1 ; i <= n ; i ++) cin>>a[i]>>b[i],q*=a[i]; for (int i = 1 ; i <= n ; i ++){ if(a[i] == 1)continue; q/=a[i]; int j=1; while(q*j % a[i] != 1)j++;//找其他幾個數的公倍數%a[i]等於一的數 c[i]=q*j; q*=a[i]; } for (int i = 1 ; i <= n ; i ++) sum+=c[i]*b[i],sum%=q; cout<<sum%q; return 0; }
注意:中國剩余定理只能用於每一個a[i]都兩兩互質的情況,但是如果它們不是兩兩互質的,我們就要用 “擴展中國剩余定理”
擴展中國剩余定理是中國剩余定理的"進階版"
那么擴展中國剩余定理的使用情況是怎么樣的呢?
因為上面也提到了:“注意,中國剩余定理的只能用於幾個模數兩兩互質的情況”,所以擴展中國剩余定理就是可以適用於模數不兩兩互質的情況。
那這怎么搞啊?
聰明的數學家們又找到了一種辦法:
將原來的余數方程列出來
假設現在我們已經求出來了前k-1個方程的解是x,現在加入了第k個方程
設前k-1個方程的模數的乘積是M,我們現在就是要求一個數字P使得
(x + P*M) % 第k個模數 = 第k個余數
這個P是可以通過擴展歐幾里得算法算出來的,所以就可以很快求出P來。
這個問題又解決了,妙啊!
