線性素數篩
int prime[MAXN], tag[MAXN]; void Get_Prime() { Mem0(tag); int cnt = 0; for(int i = 2;i < MAXN;++i) { if(!tag[i]) prime[cnt++] = i; for(int j = 0;j < cnt && i * prime[j] <= MAXN;++j) { tag[i * prime[j]] = 1; if(i % prime[j] == 0) break; } } }
這個是很多人網上給的圖。。。。這裏只是搬個圖來模擬
還是按上面的例子進行一遍模擬:N=20
下面說一下我的理解(關於網上說的兩個重點)
1、
for(int j = 0;j < cnt && i * prime[j] <= MAXN;++j)
對於這個的解釋我覺得網上的解釋實在看不懂再來看我這個比較好。。。因為我感覺我這個更難懂,但是別人的我看不懂
prime[j] 這裏存是小於或等於 i 的所有素數。關於 i * prime[j] ,我們先看一個素數 2,
如果沒有下面那個 break 的話
當 i = 3 時,這時候有 2 * 3,
當 i = 4 時,這時候有 2 * 4,(事實上程序跑到這裏就 break了)
當 i = 5 時,這時候有 2 * 5。。
類推下去,可以知道,最後算得一定範圍內和prime[j] 相關的合數(任何一個數可以用一個或多個素數相乘得到),這個些數是(prime[j] + 1 ~ i) * prime[j]
2、
if(i % prime[j] == 0) break;
網上都說這裏保證每個合數只會被它的最小質因數篩去,我就解釋一下為什麽這裏會這樣。過程裏的主要式子忘了查什麽資料哪裏瞄到的,當時搭梯子後點來點去的。
質數就不用說了,說合數,每個合數 num 都可以表示成多個質數的積(歐拉函數)
我們設一個合數為 num,這個合數的最小質因數為 a ,那麽可得 num = a^k * b;
1、當 k 為 1 時,num = a * b ( a < b)
2、當 k != 1 時,num = a^k * b
這裏註意到我們將上面代碼的合數表示為 i * prime[j] = num ;當 i % prime[j] == 0 時,那麽 prime[j] 為組成 i 的最小的質數(prime 為從小到大排列的質數組),即設 i = c * prime[j] ,那麽 num = c * prime[j] * prime[j] = prime[j]^2 * c; 這符合上面的 2,雖然這種推論沒有證明充要條件,但是應該能理解吧。。。。
那麽上面的 1 呢?不就是 num = i * prime[j] = b * a(prime[j] <= i)
線性素數篩