素数筛/分解质因数

素数筛/分解质因数

什么是素数/质数

除了1和本身之外不能被其他数整除的一类数为质数(满足对任意1 < a < nn % a != 0

,除了素数和1外的正整数都是合数,合数一定有素因子

1既不是素数也不是合数

素数的判断

根据素数的特点,我们要遍历2, 3, 4, …, n - 1,判断是否满足n % a != 0,这样判断简单直接,但复杂度在O(n),这对于一道题的一小部分来说的确有些大了

我们发现,如果在1 < a < n中,存在n的约数kn % k == 0,那么必有n / k也是n的约数,且两者必有一个小于sqrt(n),这样我们只需要遍历1 < a < sqrt(n)即可,复杂度降至O(sqrt(n))

bool isPrime(int n)
{
    if(n <= 1)
        return false;
    //注意这里,先转换为浮点型计算,结果再取成整形
    int sqr = (int)sqrt(1.0 * n);
    for(int i = 2; i <= sqr; ++i)
    {
        if(n % i == 0)
            return false;
    }
    return true;
}

那么我们要制素数表,即判断1 ~ n是否是素数,时间复杂度达O(n* sqrt(n)),可以应对**105**以下的数据规模

埃氏筛制素数表O(nloglogn)

算法从小到大枚举所有数,对每一个素数都筛去它的倍数,得到剩下的数便都是素数

例如对于1~20,事先只需确认2是质数即可

删除2的倍数

1234567891011121314151617181920
1234567891011121314151617181920

删除3的倍数

1234567891011121314151617181920
1234567891011121314151617181920

删除5的倍数

删除7的倍数

删除19的倍数

最后,我们得到了剩余的数就是1 ~ 20的素数表

const int maxn = 1e4 + 1;	//表长
int prime[maxn], pNum = 0;	//prime数组存放所有素数,pNum为素数个数
bool p[maxn];	//如果i为素数,则p[i] = false
void FindPrime()
{
    for(int i = 2; i < maxn; ++i)
    {
        if(p[i] == false)
        {
            prime[++pNum] = i;
        	for(int j = 2 * i; j < maxn; j += i)
        	{
           		p[j] = true;	//筛去所有i的倍数
        	}
        }
    }
}

输出10000以内的素数

int main()
{
    FindPrime();
    for(int i = 1; i <= pNum; ++i)
        cout << prime[i];
    return 0;
}

应用

PAT Basic Level 1013 数素数

image-20210312232551103

这道题看着简单,坑却很深

  • 坑1:输出格式,很容易出错,严格按照要求来办
  • 坑2:给的范围是在第1e4个素数之内,但是我们制素数表时需要明确最大素数范围;实测第1e4个素数的数量级为1e6,数组开到1e8会爆内存,等于这里1e7是唯一可用的数据规模!
#include <bits/stdc++.h>
using namespace::std;
const int maxn = 1e7;	//表长
int prime[maxn], pNum = 0;	//prime数组存放所有素数,pNum为素数个数
bool p[maxn] = {0};	//如果i为素数,则p[i] = false
void FindPrime()
{
    for(int i = 2; i < maxn; ++i)
    {
        if(p[i] == false)
        {
            prime[++pNum] = i;
        	for(int j = 2 * i; j < maxn; j += i)
        	{
           		p[j] = true;	//筛去所有i的倍数
        	}
        }
    }
}
int main()
{
    FindPrime();
    int a, b, cnt = 0, ans[10005];
    cin >> a >> b;
    for(int i = a; i <= b; ++i)
    {
        ans[++cnt] = prime[i];
    }

    for(int i = 1; i < cnt; ++i)
    {
        cout << ans[i];
        if(i % 10 == 0)
            cout << endl;
        else
            cout << ' ';
    }
    cout << ans[cnt];
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值