通常來講,能夠用試除法判斷某一個數是否是素數:ios
bool isPrime(int n) { if(n < 2) return false; for(int i = 2; i < n; i++) if(n % i == 0) return false; return true; }
但其實咱們只須要試除到根號n便可,由於對於任意的n,假設存在一個大於根號n的因數,那麼確定存在一個小於根號n的因數與之對應。那麼有:算法
bool isPrime(int n) { if(n < 2) return false; int m = sqrt(n + .5); for(int i = 2; i <= m; i++) if(n % i == 0) return false; return true; }
但若是咱們要求全部小於等於n的數是否是素數呢?這時咱們用素數篩法解決。篩法是一種思想,利用以前處理過的信息來更新後面的結果。對於一個大於1的數,它的倍數顯然是合數,那麼咱們能夠在遍歷到i時,篩去全部i的倍數;當咱們遍歷到i+1時,只要它尚未被篩去,那它就必定是素數。這就是埃拉託斯特尼篩法,簡稱埃氏篩。函數
int prime[M]; bool vis[M]; void eratosthenes() { for (int i = 2; i < M; i++) { if (!vis[i]) { prime[++prime[0]] = i; for (int j = 2 * i; j < M; j += i) { vis[j] = 1; } } } }
顯然埃氏篩有不少的重複的篩除操做,把樸素算法中的優化引入埃氏篩,咱們就能夠獲得改進的埃氏篩。優化
int prime[M]; bool vis[M]; void eratosthenes_plus() { int m = sqrt(M + .5); for (int i = 2; i <= m; i++) { if (!vis[i]) { prime[++prime[0]] = i; for (int j = i * i; j < M; j += i) { vis[j] = 1; } } } }
雖然改進的埃氏篩複雜度在大多數狀況已經能夠被接受了,但有時咱們須要線性時間判斷1~n的全部素數。這時就須要歐拉篩。歐拉篩經過保證每一個素數都會被它最小的那個(質)因數篩掉,進而使複雜度達到線性。ui
int prime[M]; bool vis[M]; void euler() { for(int i = 2; i < M; i++) { if(!vis[i]) { prime[++prime[0]] = i; } for(int j = 1; j <= prime[0] && i * prime[j] < M; j++) { vis[i * prime[j]] = 1; if(i % prime[j] == 0) { break; } } } }
重點就在於if(i % prime[j] == 0)這一句,爲何要在i是第j個素數的倍數時中止篩除呢?
\[ \begin{align} & 當i是prime[j]的倍數時,咱們能夠把i表示爲i=k\times prime[j],k\in N^+。\\ & 對於下一個被篩去的數X,X=i\times prime[j+1]=k\times prime[j]\times prime[j+1],\\ & 顯然X還存在一個更小的質因子prime[j],爲了符合每一個數都被最小的質因數篩去的原則,\\ & 此時應該跳出循環,不用prime[j+1]\times(k\times prime[j])篩去X,而應該在未來,\\ & 用prime[j]\times(k\times prime[j+1])篩去X。 \end{align} \]spa
在數論中,對正整數n,歐拉函數φ(n)的值爲小於或等於n的正整數中與n互質的數的個數。.net
例如:φ(8)=4,由於1,3,5,7與8互質。code
擴展:在羣論中,歐拉函數其實是模n的同餘類構成的乘法羣的階。blog
在數論中,歐拉定理爲:若gcd(a,n)=1,則:
\[ a^{\phi(n)}\equiv 1(mod\space n) \]
歐拉函數的性質和拉格朗日陪集定理結合構成了歐拉定理的證實。ci
推廣:歐拉降冪公式
\[ a^b\equiv a^{b\%\phi(n)+\phi(n)}(mod\space n) \]
例題:洛谷 5091
若n是質數p的k次冪,那麼有:
\[ \phi(n)=\phi(p^k)=p^k-p^{k-1}=(p-1)p^{k-1}\\ p^{k-1}爲1到n中p的倍數,顯然這些數與n不互質。 \]
例:
\[ \phi(72)=\phi(2^3\times 3^2)=2^{3-1}\times (2-1)\times 3^{2-1}\times (3-1)=24 \]
回顧費馬小定理:若p爲質數,a爲任意正整數,那麼:
\[ a^p-a能夠被p整除。 \]
即:
\[ \begin{aligned} &a^p-a\equiv0(mod\space p)\\ \Leftrightarrow&a^p\equiv a(mod\space p)\\ \Leftrightarrow&a^{p-1}\equiv 1(mod\space p) \end{aligned} \]
回到歐拉定理,若p爲質數,φ(p)=p-1,那麼有:
\[ a^{p-1}\equiv 1(mod\space p) \]
這就是費馬小定理。歷史上,歐拉首先證出了費馬小定理,而後在這個基礎上推廣獲得了歐拉定理。
即若m,n互質,那麼有φ(mn)=φ(m)φ(n)
對任意a>b>0,gcd(a,b)=1,總有gcd(a,a-b)=1。那麼對於n,有φ(n)個小於n的數與n互質,設其爲x,那麼總存在一個n-x也與n互質,二者之和爲n,那麼一共有φ(n)/2對。這些數的和爲n*φ(n)/2。
題意:求比n小的、和n不互質的數的和%1,000,000,007,其中n≤10的9次方。
對於任意正整數n,分解質因數得:
\[ n=p_1^{k_1}\times p_2^{k_2}\times ......\times p_m^{k_m} \]
由:
\[ \phi(p^k)=p^k-p^{k-1}=p^k(1-{1\over p}) \]
得:
\[ \phi(n)=p_1^{k_1}(1-{1\over p_1})\times p_2^{k_2}(1-{1\over p_2})\times ......\times p_m^{k_m}(1-{1\over p_m}) \]
又:
\[ n=\prod_{i=1}^m p_i^{k_i} \]
因此:
\[ \phi(n)=n\times \prod_{i=1}^m (1-{1\over p_i}) \]
代碼實現以下:(例題:poj 2407)
// 計算單個歐拉函數值 int euler(int n) { int ans = n; // 追求更高效率還能夠結合素數表 int m = sqrt(n + .5); for(int i = 2; i * i <= n; i++) { if(n % i == 0) { ans -= ans / i; while(n % i == 0) n/= i; } } if(n > 1) ans -= ans / n; return ans; }
下面是打表寫法。
LL euler[N]; void cal_euler() { euler[1] = 1; for(int i = 2; i <N; i++) { if(!euler[i]) { for(int j = i; j < N; j += i) { if(!euler[j]) euler[j] = j; euler[j] -= euler[j] / i; } } } }
題意:歐拉前綴和。注意空間限制。
#include <algorithm> #include <iostream> using namespace std; typedef long long LL; const int N = 3e6 + 100; LL euler[N]; void pre() { euler[1] = 1; for(int i = 2; i <N; i++) { if(!euler[i]) { for(int j = i; j < N; j += i) { if(!euler[j]) euler[j] = j; euler[j] = euler[j] / i * (i - 1); } } } for(int i = 2; i < N; i++) { euler[i] += euler[i - 1]; } } int main() { pre(); int a, b; while(cin >> a >> b) { cout << euler[b] - euler[a - 1] << endl; } return 0; }
在數論中,積性函數是指定義在正整數集上的算數函數f(n),且有:f(1)=1;若gcd(a,b)=1,f(ab)=f(a)f(b)。
擴展:徹底積性函數:若積性函數f在gcd(a,b)≠1時,仍有f(ab)=f(a)f(b),那麼f稱爲徹底積性函數。在數論外的積性函數通常是指徹底積性函數。
對n質因分解得:
\[ n=\prod^k_{i=1} p_i^{a_i},其中,p_i爲分解獲得的質因數 \]
那麼對於積性函數f,有:
\[ f(n)=\prod^k_{i=1}f(p_i^{a_i}) \]
歐拉函數、莫比烏斯函數、gcd(n,k)(k固定),約數函數σ(σ(n)爲n的約數個數)。約數個數函數σ定義以下:
對於任意正整數n,設其質因分解爲:
\[ n=p_1^{k_1}\times p_2^{k_2}\times ......\times p_m^{k_m} \]
那麼其因數個數爲:
\[ N=(k_1+1)\times(k_2+1)\times...\times(k_m+1) \]
\[ 即:σ(n)=\prod_{i=1}^m (k_i+1) \]