時間限制:10000ms
單點時限:1000ms
記憶體限制:256mb
描述小ho:小hi,上次我學會了如何檢測乙個數是否是質數。於是我又有了乙個新的問題,我如何去快速得求解[1,n]這個區間內素數的個數呢?
小hi:你自己有什麼想法麼?
小ho:有!我一開始的想法是,自然我們已經知道了如何快速判定乙個數是否是質數,那麼我就直接將[1,n]之間每乙個數判定一次,就可以得到結果。但我發現這個方法太笨了。
小hi:確實呢,雖然我們已經通過快速素數檢測將每一次判定的時間複雜度降低,但是n個數字的話,總的時間複雜度依舊很高。
小ho:是的,所以後來我改變了我的演算法。我發現如果乙個數p是質數的話,那麼它的倍數一定都是質數。所以我建立了乙個布林型別的陣列 isprime,初始化都為true。我從2開始列舉,當我找到乙個isprime[p]仍然為true時,可以確定p一定是乙個質數。接著我再將n以內 所有p的倍數全部設定為isprime[p*i]=false。
寫成偽**為:
isprime = true小hi:小ho你用的這個演算法叫做eratosthenes篩法,是一種非常古老的質數篩選演算法。其時間複雜度為o(n log log n)。但是這個演算法有乙個冗餘的地方:比如合數10,在列舉2的時候我們判定了一次,在列舉5的時候我們又判定了一次。因此使得其時間複雜度比o(n)要 高。primecount = 0
for i = 2 .. n
if isprime[i] then
primecount = primecount + 1
multiple = 2
while (i * multiple ≤ n)
isprime[i * multiple] = false
multiple = multiple + 1
end while
end if
end for
小ho:那有沒有什麼辦法可以避免啊?
小hi:當然有了,乙個改進的方法叫做eular篩法,其時間複雜度是o(n)的。
輸入第1行:1個正整數n,表示數字的個數,2≤n≤1,000,000。
輸出第1行:1個整數,表示從1到n中質數的個數
樣例輸入
9樣例輸出
4
開個bool陣列f記錄i是否為素數。
先全部賦為1,表示這個數為素數。
從2開始篩合數,若i為素數,則a*i,a∈z肯定為合數。
對於每乙個i,都去篩一遍,只篩素數倍,不篩合數倍,因為每個合數倍的都會被其他的比i大的數篩掉。
然後還有乙個優化,假設列舉到的素數為p,當p|i時就可以break
了。
這樣可以保證每乙個合數k都是被k/它那個最小的質因數篩掉的,證明如下:假設乙個合數
k=m*p1,p1
為其最小的質因子。則
k只會在
i=m,
primelist[j]=p1
時被篩掉一次。
首先會在
i=m,
primelist[j]=p1
時被篩掉是顯然的。因為p1是
k的最小質因子,所以
i=m的所有質因子也≥
p1。於是
j迴圈在列舉到
primelist[j]=p1
前不會break
,從而一定會在
i=m,
primelist[j]=p1
時被篩掉
其次不會在其他時候被篩掉。假設k在
i=n, primelist[j]=p2
時被篩掉了,此時有
k=n*p2。由於
p1是k最小的質因子,所以
p2 > p1
,m > n
且p1|n(
因為p2|m,n/p1==m/p2)
。則i=n,j
列舉到primelist[j]=p1時(
沒到primelist[j]=p2)
就break
了。所以不會有其他時候篩掉k。
1 #include2 #include3 #include4 #include5 #include6 #include7 #include
8 #include9 #include10 #include11 #include12 #include13 #include14
#define maxn 1000010
15using
namespace
std;
16bool
f[maxn];
17int
su[maxn];
18int
main()
1932
}33 printf("%d"
,num);
34return0;
35 }
數論二 Eular質數篩法
如何去快速得求解 1,n 這個區間內素數的個數呢?自然我們已經知道了如何快速判定乙個數是否是質數,那麼我就直接將 1,n 之間每乙個數判定一次,就可以得到結果。雖然我們已經通過快速素數檢測將每一次判定的時間複雜度降低,但是n個數字的話,總的時間複雜度依舊很高。發現如果乙個數p是質數的話,那麼它的倍數...
hihocoder 數論二 Eular質數篩法
時間限制 10000ms 單點時限 1000ms 記憶體限制 256mb 描述小ho 小hi,上次我學會了如何檢測乙個數是否是質數。於是我又有了乙個新的問題,我如何去快速得求解 1,n 這個區間內素數的個數呢?小hi 你自己有什麼想法麼?小ho 有!我一開始的想法是,自然我們已經知道了如何快速判定乙...
Eular質數篩法
任意乙個正整數k,若k 2,則k可以表示成若干個質數相乘的形式。eratosthenes篩法中,在列舉k的每乙個質因子時,我們都計算了一次k,從而造成了冗餘。因此在改進演算法中,只利用k的最小質因子去計算一次k。而在其基礎上改進的eular篩法,其偽 為 isprime true primelist...