洛谷 p3383
題目描述:如題,給定乙個範圍n,你需要處理m個某數字是否為質數的詢問(每個數字均在範圍1-n內)
資料範圍:
對於100%的資料:n<=10000000,m<=100000
樣例輸入:
100 5
2 3
4 91
97樣例輸出:
yes
yes
no no
yes
#include
#define max 100000000
using
namespace
std;
bool ifnot_prime[max+1]; //0---素數 1---不是素數
int prime[max],pnum;
void init(int n) //核心步驟,篩表操作
}}int main()
}
這麼大資料範圍不可能乙個個判斷【誤……記得有個什麼東西用費馬小定理很快就能得出乙個數是不是質數……原來學過的都忘完了orz……【【
【↑: 題解裡有個什麼叫miller_rabin的演算法就是這個思路可以看看……
因此我們想到篩選操作
引出一件小學做過的事:
小學時做過乙個100內的素數表以上便是篩選表的思路。步驟是:
1. 把所有2的倍數[4.6.8]【除了本身】劃上一條槓,標記為不是素數
2. 把3所有的倍數[6.9.12]【除了本身】也如上照做
3. 然後依次5、7、11等等之內所有的素數都如上照做
則最後得出的表,沒有劃槓的便是100以內所有的素數表
基本的操作大家肯定都會了吧(:зゝ∠)……這裡只是來講下優化
我們發現上述操作中 2 篩除了 4、6、8、10、……
3 篩除了 6、9、12、……
發現 6 分別被2、3都篩過了
如果能讓 6 只被篩一次,則效率能極大優化
因此先不管這個優化,先講第乙個優化……
首先,我們把原來的思路:
把乙個素數從頭到尾篩完,再篩下乙個素數
e.g.
先來 2 篩除 4、6、8、10、12、14、……
過後 3 篩除 6、9、12、15、……
改為—>
只篩除所找到素數的某倍數那個數,
這個倍數k從2迴圈到所要找區間的一半【如要打100000內素數表,k=2—>50000 [這是個小優化,因為原來我是直接2—>100000,發現最小素數2*這麼大早就超界了,因此只用到/2這麼多就行了]
而且 所找到的素數,是邊篩邊找的,而這個邊篩邊找恰好可以用 用來記倍數的k 來表示
【知道我的語言是聽不懂的所以來看栗子吧……
e.g.
倍數k=2 2為素數,入素數隊, 2 篩除 2*2—>4;
k=3 3為素數,入素數隊, 2 篩除 2*3—>6; 3 篩除 3*3—>9;
k=4 4不為素數,不管, 2 篩除 2*4—>8; 3 篩除 3*4—>12;【然而這裡還是會重複篩選,當k=6時 2 會篩除 12;
光是這樣做,也就是 init中 沒有 if (top % prime[c] == 0) break; 這步時
void init(int n) //核心步驟,篩表操作
}}
就已經得到了極大優化
n=10000000,用時:.374,甚至已經可以ac了orz……【
接下來便是防止重複篩選的關鍵步驟!
當倍數k不斷增長的時候,2總會把所有 2所有的倍數 給篩選完
因此 3 本應可以篩 12,但是我們為何不讓 2 把他篩了呢?
觀察一下素數隊,肯定是單調遞增的,也就是存的為 2、3、5、7、11 這樣的質數
因此這樣就更好操作了!因為每次是先讓2乘倍數k,再讓3乘再5……
因此我們讓這個倍數k,對所翻倍的素數 prime[c] 取模一下
emmmm聽不懂不要急來強行舉例解釋一波……
當top=4的時候【最早開始產生重複篩數的top 3*4=12 本應被 2 篩除e.g. 當top=9的時候,素數隊prime=1st. 2 篩除 2*2 —> 4; 發現 4%2==0, 那麼這個就代表著,4是2的倍數,也就是4可以寫成2*k(k∈z)(當然k=2)這種形式,
因此之後篩選的時候
(本來不該做這步的) 2nd. 3 應該篩除 3*4—> 12 的, 然而 由上面的 可知 4 = 2*k 因此 3*4 就可以為—> 3*2*k
換個順序 3*4 —> 2*3*k
這代表著什麼?
代表著 12 這個數 是可以被 2 在倍數為3*k的時候 篩除的!
因此就不用繼續篩下去了,坐等今後2把這個數給篩了
1st. 2 篩除 18, 9%2!=0, 證明9不能寫為 2*k (k∈z)這種形式的,因此繼續
2nd. 3 篩除 27, 9%3==0, 證明9能被寫為 3*k (k∈z)這種形式的
因此如果繼續的話 5*9 —> 3*k*5 ,即3之後可以把45這個數篩除
7*9 —> 3*k*7 ,即3之後可以把63這個數篩除
所以這裡,明智的break,讓今後3去篩他
以上 換到程式裡來
簡單的加一句 if (top % prime[c] == 0) break;
void init(int n) //核心步驟,篩表操作
}}
n=10000000,用時:.124,強無敵!……
【那個n/2+1改為n,用時也才.156,所以這個是後來才發現的小優化啦(:зゝ∠)……
以上 */
洛谷P3383線性篩素數
中體現在那個 break prime 陣列 中的素數是遞增的,當 i 能整除 prime j 那麼 iprime j 1 這個合數肯定被 prime j 乘以某個數篩掉。因為i中含有 prime j prime j 比 prime j 1 小。接下去的素數同理。所以不用篩下去了。在滿足 i prme...
洛谷 P3383 模板 線性篩素數
題目大意 如題,給定乙個範圍n,你需要處理m個某數字是否為質數的詢問 每個數字均在範圍1 n內 時空限制 500ms 128m 資料規模 對於30 的資料 n 10000,m 10000 對於100 的資料 n 10000000,m 100000 題解 數學方法 線性篩素數 很多人都是找到乙個素數,...
洛谷 P3383 模板 線性篩素數
如題,給定乙個範圍n,你需要處理m個某數字是否為質數的詢問 每個數字均在範圍1 n內 輸入格式 第一行包含兩個正整數n m,分別表示查詢的範圍和查詢的個數。接下來m行每行包含乙個不小於1且不大於n的整數,即詢問該數是否為質數。輸出格式 輸出包含m行,每行為yes或no,即依次為每乙個詢問的結果。1 ...