線性篩選素數(模板)

2021-08-08 22:33:02 字數 2213 閱讀 2149

今天hz大神回來給我們上課,首先講了線性篩選素數,就先做個記錄吧

以一道模板題為例子

洛谷題號: p3383 【模板】線性篩素數

題目描述

如題,給定乙個範圍n,你需要處理m個某數字是否為質數的詢問(每個數字均在範圍1-n內)

輸入輸出格式

輸入格式:

第一行包含兩個正整數n、m,分別表示查詢的範圍和查詢的個數。

接下來m行每行包含乙個不小於1且不大於n的整數,即詢問概數是否為質數。

輸出格式:

輸出包含m行,每行為yes或no,即依次為每乙個詢問的結果。

輸入輸出樣例

輸入樣例#1:

100 5

2 3

4 91

97 輸出樣例#1:

yes

yes

no no

yes

說明時空限制:500ms 128m

資料規模:

對於30%的資料:n<=10000,m<=10000

對於100%的資料:n<=10000000,m<=100000

樣例說明:

n=100,說明接下來的詢問數均不大於100且大於1。

所以2、3、97為質數,4、91非質數。

故依次輸出yes、yes、no、no、yes。

. .

. 分析:這模板題,肯定用線性篩選啦,我先大概說說我對線性篩選素數的理解。

這個方法主要就是用已知的質數去篩出合數。任意乙個合數都可以被質因數分解,那麼我們就可以用已知的乙個素數去篩選出乙個以這個質數為最小質因數的合數。

為什麼是篩選出乙個以這個質數為最小質因數的合數呢? 因為乙個合數的質因數可能有很多個,但是最小質因數就只有乙個。在這個演算法裡,乙個數如果是質數,就不用篩,如果是合數,就只會被它的最小質因數給篩出來。這樣就達到的o(n)的複雜度啦。

. .

. 直接上**,**裡有詳細注釋

//第一種打法

#include

#include

#include

int pd[10800100],pr[10080100];

int n,m,x,tot=0;

using

namespace

std;

void prime()

}}int main()

return0;}

//總之,在這個方法中,每個數至少被訪問一次,每個數至多被訪問一次。對於質數,一定會在i的迴圈中訪問到,並確定為質數。對於合數,一定可以分解為乙個最小素因子和其他數的乘積。

.

. .

來說說最難理解的一一句**:

if(i%pr[j]==0) break;
說明一下我對這句**的理解,可以先設x=m*a,其中m是x的最小質因數。a是x的最大因數,但不確定是質數還是合數。那麼按照那句**,如果a是質數,在迴圈結束之前都不可能找到能讓它退出迴圈的那個數。如果a是合數的話,就有a=p1*p2*p3……*pn,各個pi是a分解質因數後的各個質數(其中p1是a的最小質因數).

現在假設有乙個質數y滿足 a%y==0 ,那麼必然有y>=p1,那麼顯然y+1>p1,此時(y+1)*a這個數不可以被a篩掉,因為必然有[(y+1)*p2*p3……*pn] > (p1*p2*p3……*pn), 此時(y+1)*a這個數的最小質因數應該是p1才對,要是在這不退出迴圈,那麼乙個數就可能會被很多組的數篩選掉,雖然這裡不退出迴圈也是對的,但是就會導致時間複雜度退化。

. .

. 然後呢,第一種打法的時間複雜度雖然是o(n),但是它的常數比較的大,其實還有一種打法,更快那麼一點點。

//第二種打法

#include

#include

#include

using

namespace

std;

int n,m,pr[10000010],x,tot=0,mx[10000010],pd[10000010];

void prime()

for(int j=1;j<=mx[i]&&pr[j]*i<=n;j++)

}}int main()

return0;}

//說一下為什麼第二種會快,因為第一種打法需要很多次取餘數操作來確定是否就退出迴圈,比較耗時。第二種打法呢可以直接確定邊界,迴圈到那裡就行。這樣時間複雜度的那個常數會較小一點。

素數線性篩選

include include includeusing namespace std bool isprime 10000001 int pri 2000001 prin int findprime int maxn for int j 0 jmaxn break 當過大了就跳出 isprime i...

線性篩選素數

侵刪。題目 給出乙個正整數n,列印出所有從1 n的素數 即質數 關鍵是要找出乙個判斷乙個正整數n是否為素數的方法 傻瓜解法 n,n 2 1 include2 int main 3 12 這裡迴圈取到sqrt n 效率改進不少了 但顯然還是不夠理想 繼續往下看 普通篩選法 埃拉託斯特尼篩法 先簡單說一...

素數篩選模板

首先將2到n範圍內的整數寫下來,其中2是最小的素數。將表中所有的2的倍數劃去,表中剩下的最小的數字就是3,他不能被更小的數整除,所以3是素數。再將表中所有的3的倍數劃去 以此類推,如果表中剩餘的最小的數是m,那麼m就是素數。然後將表中所有m的倍數劃去,像這樣反覆操作,就能依次列舉n以內的素數,這樣的...