數論四大定理:
- 威爾遜定理
- 歐拉定理
- 孫子定理(中國剩余定理)
- 費馬小定理
1.威爾遜定理
在初等數論中,威爾遜定理給出了判定一個自然數是否為素數的充分必要條件。
當且僅當$p$為素數時
$(p-1)!\equiv -1(mod\ p)$
簡單點說就是,若$p$為質數,則$p$能被 $(p-1)!+1$ 整除
但是由於階乘是呈爆炸增長的,其結論對於實際使用不太多。
證明
首先,可以明確
$(p-1)\equiv -1(mod\ p)$
根據同余式的性質,我們只需要證明
$(p-2)!\equiv 1(mod\ p)$
這個式子突然就有點熟悉了,看下逆元的定義
$a\cdot a^{-1}\equiv 1(mod\ p)$
我們考慮其實就是對於 $1,2,3,...,p−2 $去找模$p$意義下的逆元,而1的逆元就是1,不需要考慮
然后根據
$x^{2}\equiv 1(mod\ p)$
可以解得
$x_{1}=1,x_{2}=p-1$
意思就是只有1,$p-1$在模$p$意義下的逆元是自己,然而這兩個數已經被我們安排了,然后逆元還有唯一性與互反性。
那么這些數自然是一一對應,所以$(p-2)!\equiv 1(mod\ p)$成立。
2.歐拉定理
如果$n,a$為正整數,且$n,a$互質,則$a^{\varphi(n)}=1(mod\ n)$
證明
將1~n中與n互質的數按順序排布:
$x_{1},x_{2},x_{3}...x_{\varphi(n)}$
我們考慮這么一些數:
$m_{1}=a*x_{1};m_{2}=a*x_{2};m_{3}=a*x_{3}...m_{\varphi(n)}=a*x_{\varphi(n)}$
需要兩個引理,證明就不詳細展開了。
1)這些數中的任意兩個都不模n同余
2)這些數除n的余數都與n互質
由1)和2)可知
數$m_{1},m_{2},m_{3}...m_{\varphi(n)}$(如果將其次序重新排列)必須相應地同余於$x_{1},x_{2},x_{3}...x_{\varphi(n)}$
故得出:
$m_{1}*m_{2}*m_{3}...m_{\varphi(n)}\equiv x_{1}*x_{2}*x_{3}...x_{\varphi(n)}(mod\ n)$
即
$a^{\varphi(n)}(x_{1}*x_{2}*x_{3}...x_{\varphi(n)})\equiv x_{1}*x_{2}*x_{3}...x_{\varphi(n)}(mod\ n)$
即
$K(a^{\varphi(n)}-1)\equiv 0(mod\ n) $這里$K=x_{1}*x_{2}*x_{3}...x_{\varphi(n)}$
可知
$K(a^{\varphi(n)}-1)$
被n整除,但$K$中的因子都與$n$互質,所以$K$與$n$互質。那么
$a^{\varphi(n)}-1$
必須能被$n$整除,即
$a^{\varphi(n)}-1\equiv 0(mod\ n) $
即
$a^{\varphi(n)}\equiv 1(mod\ n) $
得證。
3.費馬小定理
能看出來,歐拉定理是費馬小定理的推廣,所以歐拉定理也叫費馬-歐拉定理,就不詳細展開了。
順便一提一下,費馬大定理:
4.中國剩余定理(孫子定理)
問題描述
“今有物不知其數,三三數之余二,五五數之余三,七七數之余二。問物幾何?”
轉換成數學語言,就是求解一次同余式組
\begin{cases}
x\equiv\ a_1(mod\ m_1) \\
x\equiv\ a_2(mod\ m_2) \\
x\equiv\ a_3(mod\ m_3) \\
... \\
x\equiv\ a_n(mod\ m_n) \\
\end{cases}
其中$a_i, m_i$均為正數,模數$m_i$兩兩互素。
定理
令$M=\prod_{i=1}^{n}m_{i}$,即$M$是$m_i$的最小公倍數
$e_i$為$\frac{M}{m_i}\cdot e_i\equiv 1(mod \ m_i)$的最小非負整數解
則有對於原方程組有唯一解
$x=\sum_{i=1}^{k}a_ie_i \frac{M}{m_i} (mod\ M)$
代碼實現:
void exgcd(int a, int b, int& x, int& y) { if (b == 0) { x = 1; y = 0; return; } exgcd(b, a % b, x, y); int temp = x; x = y; y = temp - a / b * y; } int crt(int* a, int* m, int k) { int res, x, y, M = 1; for (int i = 1; i <= k; ++i) M *= m[i]; for (int i = 1; i <= k; ++i) { exgcd(M / m[i], m[i], x, y); if (x < 0) x += m[i]; res = (res + M / m[i] * x * a[i]) % M; } return res % M; }
模板題
https://www.luogu.org/problemnew/solution/P3868

#include <iostream> #include <fstream> using namespace std; typedef long long LL; LL m[10], a[10], k; //數據可能會爆long long LL quick_mult(LL a, LL b, LL M) { LL res = 0; while (b) { if (b & 1) res = (res + a) % M; a = (a + a) % M; b >>= 1; } return res % M; } void ex_gcd(LL a, LL b, LL&x, LL&y) { if (b == 0) { x = 1; y = 0; return; } ex_gcd(b, a % b, x, y); LL temp = x; x = y; y = temp - a / b * y; } LL crt() { LL M = 1; LL e[10]; LL except_mi[10]; for (int i = 0; i < k; i++) { M *= m[i]; } for (int i = 0; i < k; i++) { LL x,y; ex_gcd(M / m[i], m[i], x, y); if (x < 0) x += m[i]; e[i] = x; } LL res = 0; for (int i = 0; i < k; i++) { (a[i] % m[i] + m[i]) % m[i];//a[i]可能為負數,根據同余性質,取正 res = res % M + quick_mult(e[i], quick_mult(M / m[i], a[i], M), M); } return res % M; } int main() { #ifdef LOCAL fstream cin("data.in"); #endif // LOCAL cin >> k; for (int i = 0; i < k; i++) { cin >> a[i]; } for (int i = 0; i < k; i++) { cin >> m[i]; } cout << crt(); return 0; }