歐拉線性篩素數

這裏介紹兩種篩法

一般篩法(埃拉託斯特尼篩法):
基本思想:素數的倍數一定不是素數
實現方法:用一個長度爲N+1的數組保存信息(0表示素數,1表示非素數),先假設所有的數都是素數(初始化爲0),從第一個素數2開始,把2的倍數都標記爲非素數(置爲1),一直到大於N;然後進行下一趟,找到2後面的下一個素數3,進行同樣的處理,直到最後,數組中依然爲0的數即爲素數。
下面我們來介紹一波真正的線性篩(歐拉篩法):
我們發現在上面的篩法中有的數字是多個素數的倍數,也就是說它可能會被重複計算多次,比如說6同時是2與3的倍數,它在計算時就被訪問了兩次,這樣會導致效率低下,所以在下面的算法中我們考慮如何優化這種情況。

模版題

#include <iostream>
#include <cstdio>
using namespace std;

//Statement_common
int n,m,g;
int prime[10000001];      //prime[i]爲第i個素數
bool flag[10000001]={1,1};//1不是素數,0是素數
//Statement_fun
int read();

int main()
{
    freopen("P3383.in","r",stdin);
    freopen("P3383.out","w",stdout);

    cin>>n>>m;
    for(int i=2;i<=n;i++)//第一層for循環,判斷 i 是否是素數。i=2時,
                         //flag[ 2 ]=0,即是素數。將其放入素數
                         //數組prime裏面。素數個數加1。
    {
        if(!flag[i]) prime[++g]=i;
        for(int j=1;j<=g && prime[j]*i<=n;j++)
        //第二層for循環,將現有的所有素數的第 i 倍篩選掉。即 
        //flag[ i * prime [ j ] ]置爲1。
        //i=2時,僅能將4篩掉,即isnotprime[ 2 * 2 ]=1;
        {
            flag[prime[j]*i]=1;
            if(i%prime[j]==0) break;
            //原理是利用了每個合數必有一個最小素因子,每個合數僅被它的最小素因子篩去正
            //好一次,當 i 能整除 prime[ j ],那麼i * prime[ j+1 ] 這個合數肯定
            //被 prime[j] 乘以某個數篩掉,因爲 i 中有prime[j]且 i * prime[ j+1 ]
            //中也有prime[ j ]。
        }
    }
    for(int i=1;i<=m;i++)
    {
        int num;    num=read();
        if(flag[num]==1) printf("No\n");
        else printf("Yes\n");
    }
    return 0;
}

int read()
{
    int x=0,f=1; char c=getchar();
    while(c<'0' || c>'9') {if(c=='-') f=-1; c=getchar();}
    while(c>='0' && c<='9') {x=x*10+c-'0'; c=getchar();}
    return x*=f;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章