埃氏筛法:
#include <iostream> using namespace std; const int N = 1e6; int n, cnt, primes[N]; bool st[N]; void get_primes(int n) { //时间复杂度:n/2 + n / 3 + ... + n / n = n(1/2 + 1/3 + ... + 1/n)调和级数 = n (lnN + c) < nlogn for(int i = 2;i <= n;i++) { if(!st[i]) { primes[cnt++] = i; for(int j = i + i; j <= n; j += i) st[j] = true; } } } int main() { cin>>n; get_primes(n); cout<<cnt<<endl; // for(int i = 0; i < cnt; i++) // cout<<primes[i]<<" "; }
上面只要求被素数筛
线性筛:
#include <iostream> using namespace std; const int N = 1e6; int n, cnt, primes[N]; bool st[N]; void get_primes(int n) { //线性筛 for(int i = 2;i <= n;i++) { if(!st[i]) primes[cnt++] = i; for(int j = 0; primes[j] <= n / i; j++) { st[primes[j] * i] = true; if(i % primes[j] == 0) break; } } } int main() { cin>>n; get_primes(n); cout<<cnt<<endl; }
合数n只会被最小的质因数筛掉
if(i % primes[j] == 0) primes[j]一定是i的最小质因子。
primes[j]也一定是i * primes[j]的最小质因子
因为j是从小到大的,primes[j]存储的也是从小到大的质数,那么primes[j] * i也是被这个最小质因子primes[j]筛掉的。
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
一开始:i = 2, primes[0] = {2}, st[4]筛掉了, 当n很大的时候,n / i也会很大 4
i = 3, primes[1] = {2,3}, st[2 * 3]筛掉了,st[3 * 3)筛掉了 6 9
i = 4, primes[1] = {2,3}, st[2 * 4]筛掉了, 8
i = 5, primes[2] = {2,3,5}, st[2*5],st[3*5],st[5*5] 10, 15 , 25
i = 6, primes[2] = {2,3,5}, st[2*6] 12
i = 7, primes[3] = {2,3,5,7}, st[2*7],st[3*7],st[5*7],st[7*7] 14、21、35、49筛掉
i = 8, primes[3] = {2,3,5,7},st[2*8] 16
综上,当i为质数的时候,会筛掉 小于等于i的质数与i的乘积,即primes[j](j = 0-i) <= i * i的所有质数乘积都会被筛掉。
合数会被它的最小质因子筛掉,比如2的合数会全部都被2筛掉,而且只会循环primes[j] = 2的一种情况,因为i 也是 2的最小质因子,当i % 2 == 0, 就不会再循环执行判断下去。
每一个质数筛的方案都是乘以前面小于等于它的质数的到的积
当一个数等于两个质因子之和的时候,n1 * n2且n1 <= n2的时候,一定是在n2加入进来之后,通过循环遍历primes[j] * i来筛掉的,n1只会筛掉 n1 * (小于等于n1的质因子)
并且一个合数如果可以等于多种积,比如 12 = 3 * 4 = 2 * 6, 一定是通过i = 6 的时候,然后通过最小质因子2来筛掉的
筛合数的时候:是通过筛从2——到这个合数的最小质因子 的积来筛 比如9的时候,st[2 * 9] st[3 * 9]就完了。晒到它的最小质因子就结束了。
所以无论是和合数还是质数的质因子,都一定会被它的最小质因子筛掉。
质数的筛法:2 *i、3 * i 、5 * i、7 * i ……i * i
合数的筛法:2 * i、3 * i、gcd(i,{2,3,5,7,9……})最小质因数和它本身的乘积。