怎麼篩素數
直接列舉i:2
→n−1
i:2\rightarrow n-1
i:2→n−
1,如果i
ii是n
nn的因數,則n
nn一定是質數,如果找完都沒找到這樣的i
ii說明n
nn是合數,純粹是根據定義來判斷
bool
check
(int n)
return
true
;}
考慮到如果乙個數i
ii為n
nn的因數,則n
i\frac
in一定也為n
nn的因數,所以列舉i
ii和列舉n
i\frac n i
in是等價的,如圖,在5
55之前所有數都能找到與之對應的數,所以我們列舉到5
55即可,那麼5
55是怎麼來的呢?很明顯是n
\sqrt
n吶,因為這種數對的臨界就是i
ii和i
ii(當i2=
ni^2=n
i2=n
時)
bool
check
(int n)
return
true
;}
但這些依然不夠,有時我們需要得出一整段數中的質數,當然可以用上面的方法對這些數乙個乙個的判斷,但這樣太慢了,這時就要用到素數篩了
埃篩的核心思想是乙個合數一定是乙個質數的倍數(是個人都知道),所以我們只需列舉每乙個質數,然後用它的倍數篩掉合數,但是我們需要列舉質數,可是我們埃篩就是為了得到質數,那怎麼辦?
首先我們知道,當我們列舉到乙個數時,這個數要麼被篩過了,要麼還沒被篩,那麼沒篩的是否就是質數呢?答案是肯定的,因為根據質數的定義,「除了1和它自身外,不能被其他自然數整除的數叫做質數」,換句話講,乙個質數的因數只有1和他本身,所以他還沒被篩的話,就一定是質數了
void
get_prime
(int n)}}
}
剛才的篩法會重複篩掉一些,如質數2會篩6,而3也會篩6,這就慢了許多,那麼我們可不可以只篩一次呢,辦法是有的,但不告訴你,就是只篩這個合數的最小質因數
依次列舉每乙個數
若當前數沒被篩,則把這個數加入質數集合
對於每乙個數,列舉當前已知質數,並相應篩掉當前數
×列舉到
的質數當前數 \times 列舉到的質數
當前數×列舉
到的質數
,而被篩掉的那個數的最小質因數一定是列舉到的質數(為什麼看後面)
如果i
ii是列舉到的質數的倍數,停止列舉質數
先看**理解做法
bool isprime[maxn]
;int prime[maxn]
;int cnt=0;
void
get_prime
(int n)
for(
int j=
1;j<=cnt && i*prime[j]
<=n;j++)}
}//最終的prime就儲存了n以內的所有質數
if
(i%prime[j]==0
)break
;
這段程式保證了篩掉的那個數的最小質因數一定是prime[j]
理由:
第一條說明了:i
ii的最小質因數是pri
me[j
]prime[j]
prime[
j],那麼i×p
rime
[j]i×prime[j]
i×prim
e[j]
的最小質因數也是pri
me[j
]prime[j]
prime[
j]。所以,j
jj一定可以保證了篩掉的那個數的最小質因數是pri
me[j
]prime[j]
prime[
j]第二條說明了:如果到j後不break,那麼繼續篩下去會不用最小質因數篩數,是無用的
乙個作者進入過的誤區:
當i
ii還不大的時候,可能會一層內就篩去大量合數,看上去耗時比較大
但是,由於保證了篩去的合數日後將不會再被篩(總共只篩一次),複雜度是線性的。到i
ii接近 n
nn 時,你會發現每層幾乎都不用做什麼事。
最後,希望大家不要因為它快就忘記它原本的名字,它叫歐 拉 篩
質數線性篩法 O n
埃氏篩法o nloglogn 仍會重複標記合數 such as i 2時 12 2 6,先會被 2 標記已是合數 i 3時 12 3 4,又被標記了一次 我們在生成乙個需要標記的合數時,每次只向現有的數中乘上乙個質因子,並且讓它是所生成合數的最小質因子 code include include us...
演算法 線性篩質數
輸出從0 00到1000000 1000000 100000 0的所有質數。首先0 00和1 11不是質數,從2 22開始逐個判斷是否為質數。如果t tt為質數,那麼對於任意正整數k kk,k t k times t k t不是質數,因此可以將k t k times t k t篩去。如果t tt已經...
線性篩質數,線性求尤拉
本篇前半部分講線性篩質數,也叫尤拉篩,後半篇講解線性求尤拉函式。我們有一種篩質數的辦法,就是列舉每個質數,然後把這個質數的倍數都篩掉,這個做法比較簡單,在這裡不做過多介紹。尤拉篩就是在這個方法的基礎上,使得每個合數只會被它最小的那個質因子篩掉,保證了複雜度是線性的 memset isprime,1,...