工欲善其事必先利其器
首先素數是什麼?
素數就是乙個數除了1和他本身沒有其他因數的數叫做質數。
合數即為對立概念
當然,1既不是素數也不是合數
素因子是什麼?
由尤拉函式得到結論:
每乙個合數都可以寫成幾個素數相乘的形式,
這些素數即為該合數的質因子
我們的目的是建立一張素數表
範圍可達1~1e8左右
以bool陣列存放,是素數為true 否則為false
基於這些數學定義,有以下演算法
素數的高效判斷方法
v1.0 全遍歷時間複雜度為o(n)
bool is_prime_1(int n)
}return true;
}
v2.0根號優化時間複雜度為o(sqrt(n))bool is_prime_2(int n)
}return true;
}
v2.5位運算優化時間複雜度為o(sqrt(n)/2)
思路超級簡單易懂
n%2=0數必不為素數
以二進位制存放的數最後1bit一定是0,n&1=0
或者直接n%2==0特判
bool is_prime_2.5(int n)
}return true;
}
v3.0 %6篩時間複雜度為o(sqrt(n)/3)
這個方法有點genius
證明:令x≥1,將大於等於5的自然數表示如下:······ 6x-1,6x,6x+1,6x+2,6x+3,6x+4,6x+5,6(x+1),6(x+1)+1 ······可以看到,不在6的倍數兩側,即6x兩側的數為6x+2,6x+3,6x+4,由於2(3x+1),3(2x+1),2(3x+2),所以它們一定不是素數,再除去6x本身,顯然,素數要出現只可能出現在6x的相鄰兩側。這裡有個題外話,關於孿生素數,有興趣的道友可以再另行了解一下,由於與我們主題無關,暫且跳過。這裡要注意的一點是,在6的倍數相鄰兩側並不是一定就是質數。此時判斷質數可以6個為單元快進,即將方法(2)迴圈中i++步長加大為6,加快判斷速度,原因是,假如要判定的數為n,則n必定是6x-1或6x+1的形式,對於迴圈中6i-1,6i,6i+1,6i+2,6i+3,6i+4,其中如果n能被6i,6i+2,6i+4整除,則n至少得是乙個偶數,但是6x-1或6x+1的形式明顯是乙個奇數,故不成立;另外,如果n能被6i+3整除,則n至少能被3整除,但是6x能被3整除,故6x-1或6x+1(即n)不可能被3整除,故不成立。綜上,迴圈中只需要考慮6i-1和6i+1的情況,即迴圈的步長可以定為6
bool is_prime3.0(int n)
v4.0埃拉託斯特尼篩法(埃氏篩)o(nloglogn)
接近線性但不是
基本思想:找到乙個素數,不斷倍增,得到的數一定不是素數,篩去。
#includeusing namespace std;
#define max 10000000
bool prime[max];
void seek_prime()
cout<這裡有乙個小優化,j 從 i * i 而不是從 i + i開始,因為 i(2~ i-1)在 2~i-1時都已經被篩去,所以從i * i開始。
上面的小程功能是找出1~n素數個數
v5.0尤拉線性篩 o(n)
埃氏篩的缺點很明顯 :對於乙個合數,有可能被篩多次。例如 30 = 215 = 310 = 5*6……那麼如何確保每個合數只被篩選一次呢?我們只要用它的最小質因子來篩選即可
先看**後解釋
/*求小於等於n的素數的個數*/
#include#includeusing namespace std;
int main()
{ int n, cnt = 0;
int prime[100001];//存素數
bool vis[100001];
scanf("%d", &n);
memset(vis, false, sizeof(vis));//初始化假設全為素數
memset(prime, 0, sizeof(prime));
for(int i = 2; i <= n; i++)
{if(!vis[i])//不是目前找到的素數的倍數
prime[cnt++] = i;//找到素數~
for(int j = 0; j其他都還好
難理解步驟:i % prime[j] == 0,這也是該篩法的優越之處
當 i是prime[j]的倍數時
i一定會被之前prime[j]篩過
證:i = kprime[j] (可證明kprime[j+1] = prime[j]kprime[j+1],這裡prime[j]是最小的素因子,當i = kprime[j+1]時會重複篩,所以才跳出迴圈。
舉個例子 :i = 8 ,j = 1,prime[j] = 2,如果不跳出迴圈,prime[j+1] = 3,83 = 243 = 2*12,被之前prime[j],i=12篩。因為尤拉篩法的原理便是通過最小素因子來消除。
線性篩素數 尤拉篩 字首和優化
關於素數的定義 在大於1的自然數中,除了1和它本身以外不再有其他因數。判斷乙個數是否是素數 int x 要求的數 for int i 2 i sqrt x i 埃氏篩法 時間複雜度 o nloglogn int num prime 0 素數的數量 int prime 5005 放素數 int che...
素數的線性篩 尤拉函式
o n 篩選素數 includeusing namespace std const int m 1e6 10 int mindiv m 每個數的最小質因數 int prim m pnum 存素數 bool vis m void prim for int j 0 j pnum j int main 尤...
線性素數篩(尤拉篩)(超級好的MuBan)
problem 找出小於等於n的所有素數的個數。include using namespace std const int maxn 1e6 int prime maxn 尤拉線性素數篩,o n bool vis maxn 標記 int prime int n return cnt int main...