Number theory¶
公因數¶
求公因數¶
- 即輾轉相除法
\(g = gcd(x, y)\)
-
常見題目類型
-
(x, y) 透過操作達到 (x - y, y), (x, y - x)
判斷質數¶
- \(O(\sqrt{n})\)
bool isPrimes(int n){
if(n == 1) return false;
for(int i = 2; i*i<=n;++i){
if(n % i == 0) return false;
}
return true;
}
Seieve of prime¶
-
埃式篩
-
\(O(n\log{\log{(n)}})\)
// Find all primes <= n.
vector<int> prime;
bool is_prime[N];
vector<int>Eratosthenes(int n)
{
is_prime[0] = is_prime[1] = false;
for(int i = 2; i <= n; ++i) is_prime[i] = true;
for(int i = 2; i <= n; ++i) {
if(is_prime[i])
for (int j = i * i; j <= n; j += i) is_prime[j] = false;
}
for(int i = 2; i <= n; ++i)
if (is_prime[i]) prime.push_back(i);
}
-
根號優化
-
\(O(n\ln{\ln{\sqrt{n}}})\)
vector<int> prime;
bool is_prime[N];
void Eratosthenes(int n) {
is_prime[0] = is_prime[1] = false;
for (int i = 2; i <= n; ++i) is_prime[i] = true;
// i * i <= n 说明 i <= sqrt(n)
for (int i = 2; i * i <= n; ++i) {
if (is_prime[i])
for (int j = i * i; j <= n; j += i) is_prime[j] = false;
}
for (int i = 2; i <= n; ++i)
if (is_prime[i]) prime.push_back(i);
}
質因數分解預處理(Prim factorization)¶
- 一定要用這個方式寫 \(\sqrt{n}\) 的優化只能用在篩法,不然會漏掉 \(\ge \sqrt{n}\)
const int MX = 100'000;
vector<int> prime_factor[MX + 10];
auto init = []() {
for(int i = 2; i <= MX; ++i) {
if(prime_factor[i].empty()) {
for(int j = i; j <= MX; j += i) {
prime_factor[j].push_back(i);
}
}
}
return 0;
}();
質因數分解方案數¶
設 \(X\) 的質因數分解為 \(p_1^{e_1}p_2^{e_2}p_3^{e_3}...p_t^{e_t}\),則構造 n 個因數的方案數:
\[\binom{e_1 + n - 1}{e_1}\binom{e_2 + n - 1}{e_2}...\binom{e_t + n - 1}{e_t}\]
假設要把 p^3 分配給 5 個數
| p, p | __ | __ | p | __ |
可以看成往 n = 5 個空盒分配 e = 3 個相同小球
把每個盒子都加上一個小球
| p, p, p | p | p | p, p | p |
可以看成將 e + n 個小球劃分五個區間,此時會有 e + n - 1 位置可以選擇,需要選 e 個位置
p _ p _ p _ p _ p _ p _ p _ p
也就是 C(e + n - 1, e)
預處理得到所有因數¶
-
一個數的因子個數可以用開立方估計(估計大致的數量級 \(\le \sqrt[3]{x}\))
-
\(O(n\log{n})\)
const int MX = 100'001;
vector<int> divisors[MX];
int init = [] {
// 预处理每个数的因子
for (int i = 1; i < MX; i++) {
for (int j = i; j < MX; j += i) {
divisors[j].push_back(i);
}
}
return 0;
}();
高度合成數¶
- 高度合成數 (Highly Composite Numbers, HCN)** ——就是在所有比它小的正整數裡,它擁有最多的因子數。
1, 2, 4, 6, 12, 24, 36, 48, 60, 120, 180, 240, 360, 720,
840, 1260, 1680, 2520, 5040, 7560, 10080, 15120, 20160,
25200, 27720, 45360, 50400, 55440, 83160, 110880, 166320,
221760, 277200, 332640, 498960, 554400, 665280, 720720,
1081080, 1441440, 2162160
平方剩餘和預處理¶
- 也就是說次方項為奇數的乘積
const int MX = 1'000'00;
int core[MX + 1];
auto init = []() {
memset(core, 0, sizeof(core));
for(int i = 1; i <= MX; ++i) {
if(core[i] == 0) {
for(int j = 1; i * j * j <= MX; ++j) {
core[i * j * j] = i;
}
}
}
return 0;
}();
-
類似題目:
\(\lfloor \frac{N}{M} \rfloor \mod{P}\)¶
由 ref 得到
\[N = (MP)Q + r\]
將 N 模 \(M \times P\) 後,兩邊同除 M 就是結果:
\[\frac{N}{M} = PQ + \frac{r}{M}\]
- atcoder:
歐幾里得算法/帶餘數除法¶
\[gcd(a^m - b^m, a^n - b^n) = a^{gcd(m, n)} - b^{gcd(m, n)}\]
\[gcd(a^m - 1, a^n - 1) = a^{gcd(m, n)} - 1\]
F 為 fibonacci 數列 \(F_1 = F_2 = 1, \text{ 且 } F_n = F_{n - 1} + F_{n - 2}\) ,有以下結論:
\[gcd(F_m, F_n) = F_{gcd(m, n)}\]
斐蜀定理/貝祖定理(Bézout's lemma)¶
Let \(a,b \in Z\), not both zero.
Let \(d = gcd(a, b)\).
Then there exist integers \(x,y \in Z\) such that
\[ax + by = d\]
Equivalently, the set of all integer linear combinations,
\[S = \{ax + by | x, y \in Z \}\]
假設每次都從 a = 0 開始走 b 步,可以到達的位置集合
\[\{tb \text{ mod } l | t \in Z \}\]
集合大小
\[\frac{n}{gcd(l, b)}\]
是否對任意位置 \(x\),存在整數 \(t\) 使
\[tb \equiv x (\text{mod } l)\]
這等價於:
\[tb + ly = x\]