簡介
主要涉及數論方面的復習(大概是 NOIP 難度),目的為復習使用,因此與其他博客相比會更為簡略,想要更詳細的介紹也附上了相應的鏈接。
僅供大家參考,如有錯誤請指出。
內容太簡單,大佬不要噴啊。>-<
先發一部分,后面的會慢慢補。
建議配合數論做題記錄食用。
更新日志
- upd on 2021.8.31: 完成初稿。
- upd on 2021.9.1 : 學習並補充了階和原根,二次剩余。
- upd on 2021.9.9 : 添加范德蒙德卷積
逆元
求 \(ax \equiv 1 \pmod p\)
根據費馬小定理有(\(p\) 為質數):
線性求逆元\(^{[1]}\):
最大公約數
int Gcd(int x, int y) { return !y ? x : Gcd(y, x % y); }
素數
暴力:\(O(\sqrt n)\) 判斷單個 \(x\) 是否為素數。
埃氏篩:\(O(n \log n)\) 判斷 \([1 \sim n]\) 是否為素數。
歐拉篩:\(O(n)\) 判斷 \([1 \sim n]\) 是否為素數。
// 只給線篩。
int tmp[MAXN], Cnt = 0;
bool vis[MAXN];
void Init(int limit) {
for(int i = 2; i <= limit; ++i) {
if(!vis[i]) tmp[++ Cnt] = i;
for(int j = 1; j <= Cnt && i * tmp[j] <= limit; ++j) {
vis[i * tmp[j]] = true;
if(i % tmp[j] == 0) break;
}
}
}
斐蜀定理\(^{[2]}\)
設 \(d = \gcd(a, b)\),那么對於方程 \(ax + by = d\) ,一定存在一組整數解。並且對於方程 \(ax + by = z\),如果滿足 \(d \mid z\),那么方程一定有整數解,否則無整數解。
如何遍歷所有解?
另外的,可以看出 \(x, y\) 的解不是唯一的,有無窮組系數 \((x, y)\) 都能滿足 \(\gcd(a, b) = ax + by\)。並且,如果 \((x, y)\) 是一組系數,那么所有系數可以表示為
擴展歐幾里得(exgcd)\(^{[3]}\)
已知 \(a,b\),求 \(ax+by = \gcd(a,b)\) 的一組解。
int Exgcd(int a, int b, int &x, int &y) {
if(!b) { x = 1, y = 0; return a; }
int d = Exgcd(b, a % b, x, y);
int t = x;
x = y, y = t - a / b * y;
return d;
}
歐拉函數\(^{[4]}\)\(^{[5]}\)
通常計作 \(\varphi (n)\),表示小於 \(n\) 且與 \(n\) 互質的數的個數。
當 \(n\) 是質數時,\(\varphi(n) = n-1\)。
歐拉函數是一個積性函數。當 \(\gcd(n,m)=1\) 時,\(\varphi (n \times m) = \varphi(n)\varphi(m)\)。
歐拉函數的通項公式:
歐拉定理\(^{[5]}\)
當 \(a\) 與 \(p\) 互質時有 \(a^{\varphi(p)} \equiv 1 \pmod p\)。
同時有一個引理 \(a^{2\varphi(p)} \equiv a^{\varphi(p)} \pmod p\)。
然后推廣它:
Miller-Rabin 素數測試\(^{[6]}\)
我們知道素數可以表示成這種形式 \(n = d \times 2^r + 1\) ,(當然,需要特判 \(2\))。
只要這個數滿足下面兩個條件中的一個,就可以通過素數測試:
其中 \(a\) 是我們選擇的一個小質數,在 \(100\) 選擇 \(8 \sim 12\) 個就基本能保證正確性。
如果一個數是素數,一定會通過素數測試;如果一個數是合數,很大概率不會通過素數測試。
復雜度應該是 \(O(k\log^2 n)\),因為需要枚舉一個 \(r\),還有龜速乘。\(k\) 是選取的 \(a\) 的數量。
// Quick_Pow 是快速冪,Quick_Mul 是龜速乘。
bool Miller_Rabin(int n, int a) {
int d = n - 1, r = 0;
while(d % 2 == 0) ++r, d >>= 1;
int x = Quick_Pow(a, d, n);
if(x == 1) return true;
for(int i = 0; i < r; ++i) {
if(x == n - 1) return true;
x = Quick_Mul(x, x, n);
}
return false;
}
int prim_list[] = {2, 3, 5, 7, 23, 37, 47, 83, 97};
bool Prime(int n) {
if(n < 2) return false;
for(int i = 0; i < 9; ++i) {
if(n == prim_list[i]) return true;
if(n % prim_list[i] == 0) return false;
if(Miller_Rabin(n, prim_list[i]) == false) return false;
}
return true;
}
例題:SP288
BSGS\(^{[7]}\)\(^{[8]}\)
求解最小的滿足下面條件的 \(x\),保證 \(a \bot p\)。
設 \(t = i \times \left \lceil \sqrt p \right \rceil - j\),\(1 \le i,j \le \sqrt p\),然后兩邊同乘 \(a^j\),有
考慮所有 \(j \in [0,t-1]\),求出 \(ba^j\) 並把他們放入哈希表,然后枚舉 \(i\) 查找有無這個值,這樣我們就能求出一個合法的 \(x\),取最小值即可。
復雜度 \(O(\sqrt p)\),使用 map
會帶一個 \(\log\)。(所以說這個算法處理不了 \(10^{18}\) 級別的數據)
int BSGS(int a, int b, int p) {
map<int, int> Hash; Hash.clear();
b %= p;
int t = sqrt(p) + 1;
for(int i = 0; i < t; ++i) Hash[b * Pow(a, i, p) % p] = i; // 存儲 hash 值
a = Pow(a, t, p);
if(!a) return b == 0 ? 1 : -1;
for(int i = 1; i <= t; ++i) { // 看看能不能找到
int val = Pow(a, i, p);
int j = (Hash.find(val) == Hash.end()) ? -1 : Hash[val];
if(j >= 0 && i * t - j >= 0) return i * t - j; // 首先找到的一定是最小的。
}
return -1;
}
中國剩余定理(CRT)
用於求解線性同余方程,在模數互質的情況下適用。
擴展中國剩余定理(exCRT)
用於求解線性同余方程,模數互質不互質均適用。
大數翻倍法
一種暴力的,求解線性同余方程的方法。碼量和理解難度都很小。
階和原根
階 ord
由歐拉定理可知,對 \(a \in \mathbb Z, m \in \mathbb N^*\),若 \(\gcd (a,m) = 1\),則 \(a^{\varphi(m)} \equiv 1 \pmod m\)。
因此滿足同余式 \(a^x \equiv 1 \pmod m\) 的最小正整數 \(x\) 存在,這個 \(x\) 稱作 \(a\) 模 \(n\) 的階,計作 \(\delta_m(a)\)。
幾個性質:
- 1、\(a,a^2,...,a^{\delta_m(a)}\) 模 \(m\) 兩兩不同余。
- 2、若 \(a^n \equiv 1 \pmod m\) ,則 \(\delta_m(a) \mid n\)。
- 3、由 2 可以推出,如果 \(a^p \equiv a^q \pmod m\) 那么 \(p \equiv q \pmod {\delta_m(a)}\)。
- 4、設 \(m \in \mathbb N^*\),\(a,b \in \mathbb Z\),\(\gcd(a,m) = \gcd(b,m) = 1\),則
的充分必要條件是
- 5、設 \(k \in \mathbb N\),\(m \in \mathbb N^*\),\(a \in \mathbb Z\),\(\gcd(a,m) = 1\),則
原根 Origin root
定義:
設 \(m \in \mathbb N^*\),\(a \in \mathbb Z\)。若 \(\gcd(a,m) = 1\),且 \(\delta_m(a) = \varphi(m)\),則稱 \(a\) 為模 \(m\) 的原根。
原根判定定理:
設 \(m \ge 3, \gcd(a,m) = 1\),則 \(a\) 是模 \(m\) 的原根的充要條件是,對於 \(\varphi (m)\) 的所有素因數 \(p\),都滿足 \(a^{\frac{\varphi(m}{p}} \not\equiv 1 \pmod m\)
原根個數:
若一個數有原根,則它的原根個數為 \(\varphi (\varphi(m))\)。
原根存在定理:
一個數 \(m\) 存在原根當且僅當 \(m=2,4,p^{\alpha},2p^{\alpha}\),其中 \(p\) 是奇素數,\(\alpha \in \mathbb N^*\) 。
幾個用來證明原根存在的定理:
- 定理 1:對於奇素數 \(p\) ,\(p\) 有原根。
- 引理:設 \(a\) 與 \(b\) 是與 \(p\) 互素的兩個整數,則存在 \(c \in \mathbb Z\) 使得 \(\delta_p(c) = \operatorname {lcm} (\delta_p(a),\delta_p(b))\),
- 定理 2:對於奇素數 \(p\),\(\alpha \in \mathbb Z\),\(p^{\alpha}\) 有原根。
- 引理:存在模 \(p\) 的原根 \(g\),使得 \(g^{p-1} \not\equiv 1 \pmod {p^2}\)
- 對於奇素數 \(p\),\(\alpha \in \mathbb N^*\),\(2p^{\alpha}2\) 的原根存在。
- 對於 \(m \not= 2,4\) 且不存在奇素數 \(p\) 及 \(\alpha \in \mathbb N^*\) 使得 \(m = p^{\alpha},2p^{\alpha}\),模 \(m\) 的原根不存在。
最小原根的數量級:
王元在 \(1959\) 年證明了,若 \(m\) 有原根,其最小原根是不多於 \(m^{0.25}\) 級別的。(這啟發我們可以暴力找最小原根)
二次剩余
定義
一個數 \(a\),如果不是 \(p\) 的倍數且模 \(p\) 同余於某個數的平方,則稱 \(a\) 為模 \(p\) 的 二次剩余。而一個不是 \(p\) 的倍數的數 \(b\),不同余於任何數的平方,則稱 \(b\) 為模 \(p\) 的 非二次剩余。
對二次剩余求解,也就是對常數 \(a\) 解下面的這個方程:
通俗一些,可以認為是求模意義下的開方。
只會 \(p\) 為奇素數的算法,\(\text{Cipolla}\) 算法。
解的數量
對於 \(x^2 \equiv n \pmod p\),能滿足"\(n\) 是模 \(p\) 的二次剩余"的 \(n\) 一共有 \(\frac{p-1}{2}\) 個(0 不包括在內),非二次剩余有 \(\frac{p-1}{2}\) 個。
勒讓德符號
歐拉判別准則
若 \(n\) 是二次剩余,當且僅當 \(n^{\frac{p-1}{2}} \equiv 1 \pmod p\)。
若 \(n\) 是非二次剩余,當且僅當 \(n^{\frac{p-1}{2}} \equiv -1 \pmod p\)。
Cipolla 算法
找到一個數 \(a\) 滿足 \(a^2-n\) 是 非二次剩余,至於為什么要找滿足非二次剩余的數,在下文會給出解釋。 這里通過生成隨機數再檢驗的方法來實現,由於非二次剩余的數量為 \(\frac{p-1}{2}\),接近 \(\frac{p}{2}\),所以期望約 2 次就可以找到這個數。
建立一個"復數域",並不是實際意義上的復數域,而是根據復數域的概念建立的一個類似的域。 在復數中 \(i^2 = -1\),這里定義 \(i^2 = a^2 - n\),於是就可以將所有的數表達為 \(A+Bi\) 的形式,這里的 \(A\) 和 \(B\) 都是模意義下的數,類似復數中的實部和虛部。
在有了 \(a\) 和 \(i\) 后可以直接得到答案,\(x^2 \equiv n \pmod p\) 的解為 \((a+i)^{\frac{p+1}{2}}\)。
范德蒙德卷積
形似:
可以理解為在大小為 \(n\) 和 \(m\) 的兩個堆中選擇 \(k\) 個點的方案數
推論:
感覺比較顯然,把前面一個組合數轉化成 \(\binom {n}{n-i}\) 在利用上面的結論就行了。
其他的推論: