质数问题
朴素筛
筛掉所有数(素数和合数都有参与最外层循环)的倍数,for循环不在if语句里
int tot = 1;//质数个数
for(int i = 2; i <= n; i++)//2到n循环
{
if(!check[i])
{
prime[tot++] = i;//当前数为质数,存入prime[]数组
//tot加一,质数个数加一
}
for(int j = i + i; j <= n; j += i)
{
check[j] = 1;//标记合数
}
}
埃氏筛
- 基本思想:一次循环筛掉当前素数的倍数
- 缺点:存在重复筛选,比如6既可以被2筛掉,又可以被3筛掉
int tot = 1;//质数个数
for(int i = 2; i <= n; i++)//2到n循环
{
if(!check[i])//筛掉已经被质数倍数标记过的合数,避免让合数进入循环
{
prime[tot++] = i;//当前数为质数,存入prime[]数组
//tot加一,质数个数加一
for(int j = i + i; j <= n; j += i)
{
check[j] = 1;//标记合数
}
}
}
线性筛
- 中心思想:只能被最小质因子筛掉
void get_primes(int n)
{
for(int i = 2; i <= n; i ++)
{
if(!st[i]) primes[cnt ++] = i;//若当前i未被标记过,仍为0,筛选入primes数组
//当前cnt为素数个数
for(int j = 0; j < cnt && primes[j] * i <= n; j ++)//下面将利用primes[j]*i寻找合数,现在给其设定条件
{
st[primes[j] * i] = true;//找到的合数标记为1
if(i % primes[j] == 0) break;//当前数/(遍历找到)最小质因数,最差情况i为素数遍历最后为primes[cnt - 1] = i
}
}
}
循环次数 | 当前被判断的数i | prime[]素数的计数数组 | 此次循环筛掉的合数prime[j] * i |
---|---|---|---|
第一次 | 2 | [2] | 4 |
第二次 | 3 | [2,3] | 6,9 |
第三次 | 4 | [2,3] | 8 |
第四次 | 5 | [2,3,5] | 10,15,25 |
第五次 | 6 | [2,3,5] | 12 |
第六次 | 7 | [2,3,5,7] | 14,21,35,49 |
第七次 | 8 | [2,3,5,7] | 16 |
第九次 | 9 | [2,3,5,7] | 18,27 |