素數篩
阿新 • • 發佈:2021-01-22
埃氏篩
&emap;簡單來說就是從質因子從小到大擴散,篩選出合數,最終剩餘的數就是質數;
有一點優化就是對於小於x^2的來說,由於從2到x-1已經被篩選過,所以此時小於x^2的x的倍數一定已經被篩到過,所以可以跳過;
埃氏篩已經是一個比較優秀的演算法了,其時間複雜度是接近線性時間複雜度,大多數程式競賽問題也可以用埃氏篩解決;
code
int vise[1000001];
void prime(int n){
memset(vise,0,sizeof(vise));
for(int i=2;i<=n;i++){
if(vise[i]) continue;
cout<<i<<" ";
for(int j=i*i;j<=n;j+=i)vise[j]=1;//可以直接從i^2開始遍歷
}
cout<<endl;
return ;
}
線性篩
儘管埃氏篩已經非常優秀了,但是埃氏篩還是會重複遍歷某些元素,這是因為沒有指定每一個合數唯一的生成序,由於每個合數都可以進行質因子分解,那麼我們只需要按照質因子從大到小的順序生成每一個元素,那麼每一個數都只會被生成一次,而不會是多次,具體來說我們儲存每個已經被篩選到的數的最小的質因子,當某個數為質數時,最小質因子就是該數;
code
int vise[100001];
void primes(int n){
//指定一個生成順序,從而避免重複篩選
memset(vise,0,sizeof(vise));
vector<int> arr;
for(int i=2;i<=n;i++ ){
if(vise[i]==0){
vise[i]=i;
arr.push_back(i);
}
for(int j=0;j<arr.size()&&arr[j]<=vise[i]&&i*arr[j]<=n;j++){
vise[i*arr[j]]=arr[j];
}
}
for(int i=0;i<arr.size();i++)cout<<arr[i]<<" ";cout<<endl;
return;
}