素數篩法的常數優化簡單整理

2021-06-07 13:13:26 字數 1600 閱讀 3462

最普通的線性篩法, earthson的**比較優秀了

比賽的時候很少有同時卡篩法時間和空間的。

線性篩法的定義憑我自己理解就是對每個範圍內的數每個合數標記一次且僅一次,沒標記的就是素數,這樣遍歷每個數的次數就是乙個常數,因此總時間是線性的。

常用的線性篩法大多考慮的是每個合數都會拆成乙個它最小的質因子乘以某個數,所以有2種方法:

1.通過列舉每個已判別的素數p來篩掉以它為最小質因子的合數,通常從p*p到n。

2.通過列舉每個數將它與已篩出的素數順序相乘直到該數能整除某個素數為止(這樣保證了所乘素數是最小的質因子)。

這個範圍可以是1到n,也可以是(2, n]間的奇數(當然記錄素數時要加上2),也可以是(3,n] 間的(不能整除3的奇數(earthson給出了乙個))

還有乙個小技巧是位模式標記, 因為c/c++中bool 型都是乙個位元組的,如果換成1個int存32個標記位,再利用位運算,空間上會省很多大約是原來的1/8,時間上也不會多耗費多少。

另外還有乙個省空間的小技巧是將篩表迴圈使用,重複覆蓋原來的篩表(這個不再這裡贅述)。

只篩奇數的情況, 生成乙個isprime的bool陣列,不能表示2,但是也可以理解沒isprime[1]同時表示了2和3,不過這樣做沒什麼意義。

/// n=100000000  runtime=1.765000s

bool isprime[n>>1]=; /// half of the upper

void init_prime()}}

}

/// 100000000 1.375000s/// 100000000 1.375000s

對於生成prime陣列, earshson的**修改的, 也是只篩奇數, 手動新增2到prime裡就可以了,用到的是第二種方法,額外開了乙個陣列儲存素數,明顯快一些

bool isprime[n>>1]=; /// n is the upper limit of primer

int prime[6000000]; /// maxn is more than prime[0]

int init_prime1()

}return prime[0];

}

/// 100000000 0.859000s 0.875000s

這個是earthson的另乙份**

/*過濾掉了所有的2的倍數和3的倍數,所以篩表的大小變為原來的1/3(1/2*2/3),時間上也近似為原來的1/3。不過考慮到迴圈內的運算增多,其實沒那麼快。使用位模式標記曬錶的狀態,所以總的空間為n/96 + 1。*/

nu換成遞推的能節省不少時間

int primes[prime_lim] = ;

int flags[n/96 + 1] = ;

int get_prime()

nu += 2 + ((i&1) << 1);

}return primes[0];

}

素數的篩法

素數的篩法有很多種 在此給出常見的三種方法 以下給出的所有 均已通過這裡的測試 名字好長 joy 不過 很短 思路非常簡單,對於每乙個素數,列舉它的倍數,它的倍數一定不是素數 這樣一定可以保證每個素數都會被篩出來 還有,我們第一層迴圈列舉到 sqrt n 就好,因為如果當前列舉的數大於n,那麼它能篩...

(數論)素數的幾種基本篩法整理歸納

為了寫幾個模板提供以後ctrl c ctrl v 1.這種篩法是我們最開始接觸語言的時候用的最基本的方法 int getprime int n return 0 3.利用數論之中的定理整數唯一分解定理來做 vecto ctor int n if x 1 ret.push back x return ...

改進的篩素數法

最簡單的篩素數法方法就是從2開始,將所以2的倍數去掉,然後從3開始,將3的倍數去掉。根據這樣很容易寫出 下面 就是是篩素數法得到100以內的素數並儲存到primes陣列中。cpp view plain copy by morewindows const intmaxn 100 bool flag m...