使用範圍:得到[2…n]之間所以素數
說實話埃氏篩已經足夠優秀,能基本做到o(n),但歐式篩才是真正的線性篩且能在篩出質數的同時運算尤拉函式和莫比烏斯函式這兩個積性函式的運算,實用於處理數論問題。
尤拉篩拆解分析
(一)初始化
int n,pn=0;//
int num[maxl], prim[maxl],phi[maxl],mob[maxl];
其中
num[x]值域為[-1,0],表示數x是否為素數(-1)
prim[x]記錄篩出的第x+1項素數
phi[x],mob[x]分別記錄尤拉函式和莫比烏斯函式的值
(二)第一重迴圈
for
(int i =
2; i < n;
++i)
i有雙重含義,既表示當前指向的應該拿去判斷是否為素數的數有點拗口,又表示篩數的乘子(後文會解釋)
(三)判別素數
if
(num[i]
)
只要num[i]是-1就代表沒被篩除是素數,這裡同時寫了尤拉函式和莫比烏斯函式的值。
(四)第二重迴圈
for
(int j =
0; j < pn && i * prim[j]
< n;
++j)
將之前篩出的素數的i倍篩除美滋滋
(五)具體篩除操作,很關鍵
if
(i % prim[j]==0
)num[i * prim[j]]=
0;//mob[i * prim[j]] = -mob[i];
//phi[i * prim[j]] = phi[i] * (prim[j] - 1);
為什麼要i%prim[j]==0就break呢,因為如果i已經包含了prim[j]這個素因子,那麼用篩去i*prim[k] (k>j) 就沒必要了,因為可以用i增大後乘以prim[j] 來代替,這步操作真正做到了線性,即每個數隻篩一次。
到這裡線性篩就講解完了,下面附上運用線性篩和尤拉函式性質的[sdoi2008]儀仗隊題解
#include
#include
#define maxl 40000
using
namespace std;
void
prime
(int
*num,
int*prim,
int*phi,
int*mob,
int n,
int&pn)
for(
int j =
0; j < pn && i * prim[j]
< n;
++j)
num[i * prim[j]]=
0;mob[i * prim[j]]=
-mob[i]
; phi[i * prim[j]
]= phi[i]
*(prim[j]-1
);}}
}int
main()
線性篩 區間篩
求l到r之間的素數1 l 231 1 1 leq l 1 l231 1由於範圍過大只需要求得r 2 sqrt 2 2r 線性篩素數時間複雜度o n int n,m int prime 100000 vis 100005 void primes int n for int j 1 j m j 區間篩素...
線性篩(尤拉篩)
昨天的考試跪的一塌糊塗 第一題水過,第二題帶wa的樸素,最後題忘了特判左端點全跪,分數比起預計得分整整打了個對折啊!步入正題 線性篩 尤拉篩 一般的篩法 ppt裡叫埃拉託斯特尼篩法,名字異常高貴 的效率是o nlglgn 其實很接近o n 啊!對於一些例如n 10000000的殘暴資料會跪,於是,線...
尤拉篩 線性篩
實現 include using namespace std const int max n 1e8 int prime max n cnt bool st max n 使用bool陣列節省空間 void is prime int n intmain 每個合數只被自己最小的質因子篩去。現在證明在i ...