資訊競賽的數學
暖身
冷知識:數學的分類
數奧四大項:
- A: 代數
- C: 組合
- G: 幾何
- N: 數論
非競賽 e.g. 微積分
油宅四大項:
- A: 動畫
- C: 漫畫
- G: 遊戲
- N: 小說
其他 e.g. ???
結論: 數奧國手和油宅有很大的相似之處
VS.
有趣的題目
計算 \(a^b\)
次方
硬做?
複雜度: \(O(b)\)
好像有點慢...
快速冪:考慮分治
想計算\(a^b\),若已知 \(c=a^{\lfloor \frac{b}{2}\rfloor}\)
若 \(b\) 是偶數,則 \(a^b=c^2\)
若 \(b\) 是奇數,則 \(a^b=a \times c^2\)
複雜度: \(O(logN)\)
扣(遞迴版)
int exp(int a, int b, int m){
if(b==0) return 1;
if(b%2){
return a*exp(a,b-1,m)%m;
} else{
int tmp=exp(a,b/2,m);
return tmp*tmp%m;
}
}
扣(迭代版)
int exp(int a, int b, int m){
int c=1, e=a;
while(b>0){
if(b%2){
c=(c*e)%m;
}
e=(e*e)%m;
b/=2;
}
return c;
}
矩陣
矩陣
某個看起來很像二維陣列的東西
橫的稱為列
直的稱為行
矩陣加法
對應的位置相加
矩陣乘法
將一 \(m\times n\)的矩陣 \(A\) 和 \(p\times q\)的矩陣 \(B\) 相乘
條件: \(n\) 必須等於 \(p\),相乘後的矩陣 \(C\) 為 \(m\times q\)
且\(C_{ij}=\sum_{k=1}^{n}A_{ik}B_{kj}\)
typedef vector<vector<int> > matrix;
matrix mul(matrix a, matrix b){
matrix c=matrix(a.size(),vector<int>(b[0].size(),0));
for(int i=0;i<a.size();i++){
for(int j=0;j<b[0].size();j++){
for(int k=0;k<a[0].size();k++){
c[i][j]+=a[i][k]*b[k][j];
}
}
}
return c;
}
複雜度: \(O(n^3)\)
還能更快?
矩陣快速冪
矩陣乘法 -> 矩陣冪 -> 矩陣快速冪
作法就把前面實數乘法改成矩陣乘法
複雜度: \(O(n^3logk)\)
OJDL 7052
TIOJ 2151
https://tioj.ck.tp.edu.tw/problems/2151
去年有趣的校內賽題
高斯消去
組合
排列數與組合數
\(C_m^n\) : \(n\) 個相異物品取 \(m\) 個的方法數
\(C_m^n=\frac{n!}{m!(n-m)!}\)
\(P_m^n\) : \(n\) 個相異物品取 \(m\) 個排成一排的方法數
\(P_m^n=\frac{n!}{(n-m)!}\)
計算
\(O(N)\)預處理階乘
或是利用性質
\(C_m^n=C_{m-1}^{n-1}+C_m^{n-1}\)
TIOJ 2163
https://tioj.ck.tp.edu.tw/problems/2163
題敘有點長 自己看
許多組合題使用DP的技巧
詳情見8e7orz的講義
數論
是什麼
關於"整數"的學問
(有時也會討論有理數)
同餘
同餘--定義
\(a\equiv b (mod m)\)
表示a除以m的餘數和b除以m的餘數相同
如: \(9\equiv 2 (mod\ 7)\)
同餘--性質
加法: \(a\equiv b (mod m) \Leftrightarrow a+c\equiv b+c (mod m) \)
乘法: \(a\equiv b (mod m) \Rightarrow ac\equiv bc (mod m) \)
注意: 不一定能除
整除
整除符號 \(a\mid b\)
表示存在一整數 \(k\) 使得 \(b=ak\)
ex. \(3\mid 12、87\mid 0、-2\mid 22\)
GCD與LCM
gcd: 最大公因數
lcm: 最小公倍數
\(gcd(a,b)\times lcm(a,b) = a\times b\)
why?
如何求?
輾轉相除
性質:\(gcd(a,b)=gcd(b,a\% b)\)
當其中一個為0時,gcd就是另一個
int gcd(int a, int b){
if(b==0) return a;
return gcd(b,a%b);
}
複雜度: \(O(logN)\)
Why?
模下的線性方程
我們想解這個
\(ax\equiv b (mod m)\)
不能除怎麼辦?
模逆元
一數字 \(a\) 在模 \(m\) 下的模逆元 \(a^{-1}\) 滿足
- \(0< a^{-1}< m\)
- \(a\cdot a^{-1}=1\)
不一定存在! 條件: \(gcd(a,m)=1\)
如何求?
費馬小定理
給定一質數 \(p\) 與一比 \(p\) 小的數 \(a\),恆有
證明?
如何求?
\(a^{p-1}\equiv 1\ (mod\ p)\)
\(\Rightarrow a\cdot a^{p-2}\equiv 1 (mod p)\)
所以 \(a^{p-2}\) 即為 \(a\) 的模逆元
非質數的情況
擴展歐幾里德(增強輾轉相除)
貝祖定理: 對於兩數 \(a,b\),存在無限多組整數 \(x,y\)
使得 \(ax+by=gcd(a,b)\)
作法
已知 \(gcd(a,m)=1\)
我們想找到一個 \(b\),使得 \(ab\equiv 1 (mod m)\)
存在 \(k\) 使得 \(ab-mk=1\)
給定 \(a,m\),求出 \(b,k\) 即可!
遞迴看看
想要求\(ax+by=1\)的解
若已知 \(x',y'\) 滿足 \(bx'+(a\%b)y'=1\)
要怎麼得到解?
實作
void extgcd(int a, int b, int &x, int &y, int &d){
if(b==0){
d = a;
x = 1;
y = 0;
return;
} else {
extgcd(b, a % b, x, y, d);
int nx, ny;
nx = y;
ny = x - a/b * y;
x = nx;
y = ny;
return;
}
}
OJDL 7044
質數
求某個數是不是質數
bool isPrime(int n){
for(int i=2;i*i<=n;i++){
if(n%i==0){
return false;
}
}
return true;
}
複雜度: \(O(\sqrt N)\)
求\(1\)~\(N\)的所有質數
用上一頁的方法一個一個硬做
複雜度: \(O(N\sqrt N)\)
好像有點慢...
埃拉托斯特尼篩法
做法: 一開始所有數都是質數,
從 \(2\) 開始,將自己所有的倍數都標記為"不是質數"
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|
How fast?
複雜度: \(N\cdot \sum_{k=1}^{N} \frac{1}{k}=O(NlogN)\)
優化:
- 可以遇到質數再開始篩
- 不用從 \(2i\) 開始跑,可以從 \(i^2\)
最終複雜度: \(N\cdot \sum_{p\leq N} \frac{1}{p}=O(N log log N)\)
跟線性差不了多少(?
Code
const int MAXN=1E5;
bool isPrime[MAXN+1];
void getPrimes(){
for(int i=0;i<=MAXN;i++) isPrime[i]=1;
isPrime[0]=isPrime[1]=0;
for(ll i=2;i<=MAXN;i++){
if(isPrime[i]){
for(ll j=i;i*j<=MAXN;j++){
isPrime[i*j]=0;
}
}
}
}
線性篩 by Euler
我們想要每個合數都被篩掉一次!
每個合數\(N\)都有最小質因數 \(p_{min}\)
我們想在 \(i=\frac{N}{p_{min}}\)時被篩掉
作法
若目前在 \(i\) 且沒被篩掉,則 \(i\) 為質數。
維護一個目前的所有質數的陣列,對於每個質數 \(p\) :
- 若 \(p\times i>N\) 則跳出
- 否則 \(p\times i\) 是合數,且 \(p\) 是 \(p\times i\) 的最小質因數
- 若 \(i\) 為 \(p\) 的倍數,則跳出
Huh?
- 若 \(i\) 為 \(p\) 的倍數,則跳出
\(p\) 會是 \(i\) 的最小質因數,所以後面的數會被 \(p\) 篩掉,不用急!
複雜度: \(O(N)\)
Code
const int MAXN=1E5;
bool isPrime[MAXN+1];
vector<int> primes;
void getPrimes(){
for(int i=0;i<=MAXN;i++) isPrime[i]=1;
for(int i=2;i<=MAXN;i++){
if(isPrime[i]) primes.push_back(i);
for(auto p:primes){
if(i*p>MAXN) break;
isPrime[i*p]=0;
if(i%p==0) break;
}
}
}
質因數分解
維護\(1\)~\(\sqrt N\)的質數,再一個個驗證
原因: 對於一個數字\(N\),至多一個質因數大於\(\sqrt N\)
EasyLa
vector<int> primes; //用前面質數篩法預處理好
vector<pii> factorize(int n){
vector<pii> vec;
pii tmp;
for(auto p:primes){
if(p*p>n) break;
if(n%p==0){
tmp={p,0};
while(n%p==0){
tmp.S++;
n/=p;
}
vec.push_back(tmp);
}
}
if(n>1) vec.push_back({n,1});
return vec;
}
TIOJ 1668
中國剩餘定理
有物不知其數,三三數之剩二,五五數之剩三,七七數之剩二。問物幾何?
<孫子算經>
下卷第二十六題 物不知數
方法1. 構造解
模 \(m_1\) 為 \(1\)
模 \(m_2\) 為 \(0\)
模 \(m_1\) 為 \(0\)
模 \(m_2\) 為 \(1\)
如果只有兩條式子
方法1. 構造解
推廣到 \(n\) 條式子的情形
定義 \(M_i=\prod_{k=1,k\neq i}^{n} m_k\)
\(\mu_i=M_i^{-1}(mod m_i)\)
則 \(M_i\mu_i\) 在模 \(m_i\) 時為\( 1\),
在模其他的 \(m_j\) 為 \(0\),故構造
方法2. 擴展歐幾里德
一樣先考慮兩條式子
方法2. 擴展歐幾里德
\(m_1k_1-m_2k_2=a_2-a_1\)
\(ax+by=c\) ?
若 \(a_2-a_1\nmid gcd(m_1,m_2)\) 則無解
否則可以求出 \(k_1\) 的值,然後代回去
得到某種 \(x\equiv m_1k_1+a_1 (mod lcm(m_1,m_2))\)
剩下\(n-1\)條式子,可以繼續做下去
計算幾何
大部分是資芽講義抄來的
內積、外積
typedef pair<int,int> pii;
#define F first
#define S second
//內積
int operator*(const pii &a, const pii &b){
return a.F*b.F+a.S*b.S;
}
//外積
int operator^(const pii &a, const pii &b){
return a.F*b.S-a.S*b.F;
}
多邊形有向面積
線段相交
給定兩線段,求是否相交
可以發現若兩線段相交,只有兩種case:
(1) 一線段的一個端點在另一線段上
(2) 兩線段的兩端點都分別在另一線段兩側
Case 1
Case 2
不相交
四個點只要有一個就可
兩邊都要判
Code
極角排序
給定一堆點,將他們依照對原點的角度排序
方法一: sort by angle
bool cmp1(pii a, pii b){
return atan2(a.S,a.F)<atan2(b.S,b.F);
}
方法二: sort by cross
bool cmp2(pii a, pii b){
bool f1 = a<pii(0,0);
bool f2 = b<pii(0,0);
if(f1!=f2) return f1<f2;
return a^b>0;
}
基本上建議用方法二,因為不會有浮點數誤差的問題
凸包
給定很多點,將所有點用最小的凸多邊形包起來,
稱為凸包。
作法
分別考慮上半部和下半部
將所有點先照座標排序,依序考慮每個點
開一個stack(或是vector)紀錄目前的凸包
類似單調對列的概念,每加進一個點,就看哪些點必須被移除
紅點加入後
移除藍點
紅點加入後
保留藍點
大家可以練習一下
數學
By jass921026
數學
- 1,841