1. 程式人生 > >質數及線性篩

質數及線性篩

最小 進行 i++ can mes 復雜 ... ace 方便

質數與線性篩

####本文將詳細將接OI中對於質數的篩法

1.基本篩法

對於一個合數 N ,一定存在一個能夠整除 N 的數介於 2 - sqrt{N} 。

正確性顯然,只需反證即可。
所以只需要對 2 - sqrt{N} 的數掃一遍即可

bool  simple( int  a ){
    for( int  i = 2 ; i <= sqrt(a) ; i++ )
        if( a % i == 0 ) return false ;
    return true ;
}

2. Eratosthenes篩法

這個篩法是我在初學時經常使用的,原因是既方便又好寫,對於 部分水體 或者 不是以篩質數為主要目的題 的可以快速寫完。

其原理大致如下

篩法執行過程
2 3 4 5 6 7 8 9 10 11  ...
T   F   F   F   F
2 3 4 5 6 7 8 9 10 11  ...
T T F   F   F F F
2 3 4 5 6 7 8 9 10 11  ...
T T F T F   F F F
2 3 4 5 6 7 8 9 10 11  ...
T T F T F T F F F
2 3 4 5 6 7 8 9 10 11  ...
T T F T F T F F F  T

我們對於從2開始的每一個數,先進行掃描,如果沒有 False 標記,則表明這個數之前的所有數都無法整除它,將其加入質數表,並將其倍數都打上 False 標記 。

先上代碼

int  num ,  tot , d[ maxn ] ;
bool used[ maxn ] ;

void  Eratosthenes(){
    for( int  i = 2 ; i <= num ; i++ ){
        if( !used[ i ] ){
            tot++ ;
            d[ tot ] = i ;
            for( int  j = i ; j <= num/i ; j++ )
                used[ i*j ] = true ;
        }
    }
}

int  main(){
    scanf("%d",&num);
    Eratosthenes();
    for( int  i = 1 ; i <= tot ; i ++ )
        printf("%d ", d[ i ] ) ;
    return 0 ;
}

埃氏篩的復雜度接近線性,達到了 N(N logN logN )。但是埃氏篩對部分有多個因數的數進行了多次刪除,以至於可能被卡掉。所以我們有了優化後的線性篩法


3.線性篩法

既然有部分數會被多個質因子篩重復篩,那麽,我們只需要讓每個合數只被它的最小質因子篩一次即可。
在這裏給出具體的思路和代碼

#include<bits/stdc++.h>
using namespace std;

int  used[ maxn ] , p[ maxn ] , num , tot = 0 ;

void  Primefactor(){
    for( int  i = 2 ; i <= num ; i++ ){
        if( used[ i ] == 0 ){
            tot++ ;
            used[ i ] = i ; p[ tot ] = i ;
        }
        for( int  j = 1 ; j<= tot ; j++ ){
            if( p[ j ] > used[ i ] || p[ j ] > num/i )break ;
            used[ i * p[ j ] ] = p[ j ] ;
        }
    }
}

int  main(){
    scanf( "%d",&num );
    Primefactor() ;
    for( int  i = 1 ; i <= tot ; i ++ )printf( "%d ",p[ i ] ) ;
    return 0 ;
}

質數及線性篩