1. 程式人生 > >線性素數篩

線性素數篩

oid ont mem rim 為什麽 ++ ima 範圍 一個數

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)

線性素數篩