數論
卓育安
講師介紹
-
227
-
數讀負責人
-
handle: prairie2022
我讀書少,又是鄉下來的,沒寫過多少程式,
所以我只能默默的看著別人上分,時不時標個電,
有時間也當個資讀講師,這樣好像可以假裝自己是資訊組。
大綱
仙貝知識
記號
以下\(p\)代表質數,\(m\)代表正整數
其他字母默認為整數
歐幾里得
輾轉相除法
int GCD(int a, int b){
if(!b){
return a;
}
return GCD(b, a%b);
}
因為每輾轉兩次\(a\)和\(b\)都至少減半,故複雜度為\(\mathcal{O}\left(\log \min(a, b)\right)\)
內建函式
//for c++14
#include <algorithm>
using namespace std;
int a=32725, b=48763;
int g = __gcd(a, b);
//g = 11快速冪
#define int long long
using namespace std;
const int m = 1e9+7;
int fastpow(int a, int n){
if(!n){
return 1;
}
if(n&1){
return (a*fastpow(a, n^1))%m;
}
int tmp = fastpow(a, n>>1);
return (tmp*tmp)%m;
}\(\mathcal{O}(\log n)\)
其實矩陣乘法也是一種函數合成
中國剩餘定理
若\(m_1, m_2, \cdots, m_n\)兩兩互質
設\(\displaystyle\prod_{i=1}^n m_i=M\)
則以上同餘方程在\(\displaystyle\operatorname{mod} M\)下有唯一解
Proof
笛卡爾積
數列
數論函數
質因數分解
因數個數
因數總和
歐拉函數
性質
質數
質數計數函數
\(\pi (n)\)為不超過\(n\)的質數個數
質數定理
而對於\(n>1\)都有
質數判定
因為一個合數必有不超過\(\lfloor\sqrt{n}\rfloor\)的質因數,故試除\(\left[\ 2,\sqrt{n}\ \right]\)中的所有整數即可判斷
\(\mathcal{O}(\sqrt{n})\)
為隨機化算法,但在特定範圍內可以只驗很少個base而確定一個數是否為質數
\(\mathcal{O}(k\log^3 n)\),其中\(k\)為base的個數
質數篩
如何得到所有不超過\(n\)的質數?
篩法
那每次要篩掉哪些倍數呢?
Solution 1
篩掉全部的倍數
#include <vector>
#include <bitset>
using namespace std;
bitset<10000000> visited;
vector<int> prime;
void sieve1(int n){
//初始化
visited.reset();
prime.clear();
//篩法
for(int i=2; i<=n; i++){
if(!visited[i]){
prime.push_back(i);
}
for(int j=i<<1; j<=n; j+=i){
visited[j] = 1;
}
}
}Solution 2
埃氏篩
只篩掉質數的倍數
#include <vector>
#include <bitset>
using namespace std;
bitset<10000000> visited;
vector<int> prime;
void sieve2(int n){
//初始化
visited.reset();
prime.clear();
//篩法
for(int i=2; i<=n; i++){
if(!visited[i]){
prime.push_back(i);
for(int j=i<<1; j<=n; j+=i){
visited[j] = 1;
}
}
}
}Solution 3
線性篩
保證每個數都只被篩到一次
#include <vector>
#include <bitset>
using namespace std;
bitset<10000000> visited;
vector<int> prime;
void sieve3(int n){
//初始化
visited.reset();
prime.clear();
//篩法
for(int i=2; i<=n; i++){
if(!visited[i]){
prime.push_back(i);
}
for(const auto &k: prime){
if(i*k>n) break;
visited[i*k] = 1;
if(i%k==0) break;
}
}
}保證\(k\)是\(ik\)的最小質因數
只篩掉每個數的質數倍
//篩法
for(int i=2; i<=n; i++){
if(!visited[i]){
prime.push_back(i);
}
for(const auto &k: prime){
if(i*k>n) break;
visited[i*k] = 1;
if(i%k==0) break;
}
}保證\(k\)是\(ik\)的最小質因數
只篩掉每個數的質數倍
因此,所有合數都只會被自己最小的質因數篩掉
故複雜度為\(\mathcal{O}(n)\)
線性篩的應用
求\(2\sim n\)的\(\varphi\)值
因此可以遞迴出\(\varphi(\text{合數})\)的值
求\(1\sim n\)的質因數分解
模運算
Euler's theorem
Fermat's little theorem
Proof
Proof
\(\displaystyle\prod_{i\in A}i=\prod_{x\in A'}x\equiv\)
\(\displaystyle\prod_{i\in A}ia=a^{\varphi(n)}\)
\(\displaystyle\prod_{i\in A}i\pmod{m}\)
Proof
\(\displaystyle 1\equiv\)
\(\displaystyle a^{\varphi(m)}\)
\(\displaystyle\pmod{m}\)
可以幹嘛
簡化冪次的計算
模逆元
\(\varphi(m)\)已知時,計算模逆元為\(\mathcal{O}(\log\varphi(m))\)
計算模逆元
\(a\div b\) 但 \(b\not\perp m\)
\(a\div b\) 但 \(b\not\perp m\)
另解
輾轉相除法
Bézout's identity
我們可以用輾轉相除法構造出一組解\(x, y\)
可遞迴出\(ax+by=g\)的最小解
int x, y, g;
void euclid(int a, int b){
if(!b){
x = 1;
y = 0;
g = a;
return;
}
euclid(b, a%b);
swap(x, y);
y -= a/b*x+a/g;
x += b/g;
}\(\mathcal{O}(\log a)\)
組合計數
二項式係數
帕斯卡三角形
\(\binom{n}{m}=\binom{n-1}{m-1}+\binom{n-1}{m}\)
- \(\mathcal{O}(m)\)計算\(\displaystyle\binom{n}{m}\)
- \(\mathcal{O}(N^2)\)計算所有\(n\leq N\)的二項式係數
如果\(n\)太大時,要計算\(\displaystyle\binom{n}{m}\operatorname{mod} M\)
因為需要取模逆元,故為\(\mathcal{O}(m+\log M)\)
到此,我們可以
數學
其他組合計數
排容原理
題單
48% of Mathematics
TIOJ經典題(?
CF隨便找
-
Divisible Numbers (10/16)
-
Intersection and Union (10/17)
-
Counting Arrays (10/20)
-
Conditional Mix (10/29)
-
ConstructOR (11/12)
Special Round
-
Count GCD (11/6)
-
Anti-median (11/20)
-
Doremy's Pegging Game (11/26)
-
Torus Path (11/27)
參考資料
-
撞董簡報
-
校培簡報
-
維基百科
-
CSES
-
CF
-
Competitive Programmer’s Handbook
Math
By prairie2022
Math
- 179
