數論仍是有不少沒學完 只是小小的總結數組
1.反身性:\(a\equiv a (mod m)\)
2.對稱性:若\(a\equiv b(mod m)\),則\(b\equiv a (mod m)\)
3.傳遞性:若\(a\equiv b(mod m)\),\(b\equiv c(mod m)\),則\(a\equiv c(mod m)\)
4.同餘式相加:若\(a\equiv b(mod m)\),\(c\equiv d(mod m)\),則\(ac\equiv bd(mod m)\)
5.同餘式相乘:若\(a\equiv b(mod m)\),\(c\equiv d(mod m)\),則\(ac\equiv bd(mod m)\)app
最大公約數:GCD
展轉相除法:設\(gcd(a,b)\)爲\(a\)與\(b\)的最大公約數函數
當\(b\)爲0時,此時的\(a\)即爲兩者的最大公約數優化
long long gcd(long long a, long long b) { return b ? gcd(b, a % b) : a; }
最小公倍數:LCM
記\(d=gcd(a,b)\),\(a=a'd\),\(b=b'd\),能夠看出 \(lcm(a,b)=\frac{ab}{gcd(a,b)}\)ui
給定\(a\),\(b\)兩個數,若b能整除a,記做\(b\mid a\),反之記做\(a\nmid b\)
簡單定理:spa
對於任意一個大於1的天然數,只有1和它自己兩個因子,則稱爲素數
素數定理:小於等於x的素數個數 \(\approx \frac{x}{\ln x}\) ,能夠用來估計素數個數,進而估算所開數組的大小
不是素數的大於1的天然數稱爲合數code
素數篩法:get
複雜度:\(O(\log{n})\)
因爲任意一個數\(x\)的因子可看爲兩部分,小於\(\sqrt{x}\)與大於\(\sqrt{x}\),所以能夠枚舉全部\(\{i\mid i\le \sqrt{x}\}\),如若出現\(i\mid x\),則不是素數,反之是素數。
通常用於對某單個數的素性斷定io
bool check(int x) { int end = sqrt(x); for (int i = 2; i <= end; ++i) { if (x % i == 0) return false; } return true; }
拓展內容(求單個合數的最大質因數)
對於任何一個數\(x\),能夠將他進行質因數分解,且同時保證\(prime[i]^2\le x_{cur}\)進行優化。
首先能夠預處理出全部\(\{prime\mid prime \le \sqrt{x}\}\),這樣\(x\)的質因數分解必定是在這個集合中,或者只有最大質因數不在這個集合中。若是所剩下的最後一個數爲1,即完美的進行了質因數分解,則最大質因數爲最後一次除的質數,反之則最後剩下的數即爲最大質因數class
const int maxn = 10000; int vis[maxn]; int cnt, prime[maxn/10]; void Euler_Sieve() { for (int i = 2; i < maxn; ++i) { if (!vis[i]) prime[cnt++] = i; for (int j = 0; j < cnt && prime[j] * i < maxn; ++j) { vis[prime[j] * i] = true; if (i % prime[j] == 0) break; } } } int Maximum_prime_factor(int x) { int ans; for (int i = 0; i < cnt && prime[i] * prime[i] <= x; ++i) { if (x % prime[i] == 0) { ans = prime[i]; while (x % prime[i] == 0) x /= prime[i]; } } return x == 1 ? ans : x; }
複雜度:\(O(\log{\log{n}})\)
因爲對於任何合數而言,他們可以被任意\(prime\) 整除,因此,能夠經過枚舉\(k*prime(k*prime\le lim_{up})\),來篩選出一些約數,而沒有被篩選過的天然就是素數
值得說明的是:當選中某個\(prime\)時,比\(prime\)小的質數的倍數已經被篩出了,因此爲了減少時間複雜度,能夠從\(prime^2\)開始篩選
const int maxn = 10000; bool vis[maxn]; int cnt, prime[maxn / 10]; void Eratosthenes_Sieve() { for (int i = 2; i < maxn; ++i) { if (vis[i]) continue; prime[cnt++] = i; for (int j = i * i; j < maxn; j += i) vis[j] = true; } }
拓展內容(求出多個合數的最大質因數)
利用埃氏篩法是由小質數到大質數的篩選過程,每次大質數篩選時會覆蓋以前小質數的結果,所以能夠獲得實現代碼
注意:開始條件從\(i^2\)變爲了\(2i\)
#include<cstdio> const int maxn = 10000; int vis[maxn]; int cnt, prime[maxn / 10]; void get_Maximum_prime_factors() { for (int i = 2; i < maxn; ++i) { if (vis[i]) continue; prime[cnt++] = i; for (int j = 2*i; j < maxn; j += i) vis[j] = i; } }
複雜度:\(O(n)\)
經過對每一個合數,只用其最小的質因數進行篩選的思想,每次將\(cur*prime[i]\)對應的數篩出,爲了保證最小的質因數篩出,當\(prime[i]\mid cur\)時,須要break
緣由在於設\(cur=k*prime[i]\),那麼若是繼續篩即對於
則能夠看出來,這個數\(n\)本應該在枚舉到數\(k*prime[i+1]\)(比\(cur\)大)被\(prime[i]\)篩出
void Euler_Sieve() { for (int i = 2; i < maxn; ++i) { if (!vis[i]) prime[cnt++] = i; for (int j = 0; j < cnt && prime[j] * i < maxn; ++j) { vis[prime[j] * i] = true; if (i % prime[j] == 0) break; } } }
拓展內容(求出多個合數的最小質因數)
利用歐拉篩每一個數都被其最小質因數所篩去
注意:開始條件從\(i^2\)變爲了\(2i\)
#include<cstdio> const int maxn = 10000; int vis[maxn]; int cnt, prime[maxn / 10]; void get_Maximum_prime_factors() { for (int i = 2; i < maxn; ++i) { if (!vis[i]) vis[i] = prime[cnt++] = i; for (int j = 0; j < cnt && prime[j] * i < maxn; ++j) { vis[prime[j] * i] = prime[j]; if (i % prime[j] == 0) break; } } }
待學
待學