ACM基础数论(一) 素数与素数筛

一、素数定义

素数又称为质数,是指大于1的自然数中除了1和它本身没有其他因子的数字。

二、素数的朴素判断方法

对于一个数字N来说,判断他是否是素数,朴素的算法则需要枚举他的所有可能的因子,判断是否能够整除,如果能够整除则不是素数。

bool isprime(int n)
{
    bool flag = true;
    for(int i = 2;i < n;i++)
        if(n % i)
        {
            flag = false;
            break;  
        }
    return flag;
}

我们注意到,一个数字的所有因子都是都是成对存在的,一个因子分布在区间 [ 1 , sqrt(n) ]另一个分布在[ sqrt(n) , n],所以只需要枚举到根号n就可以判断一个数字是不是素数.

bool isprime(int n)
{
    bool flag = true;
    for(int i = 2;i <= sqrt(n) + 1;i++)//一般会枚举多一个,防止因为精度问题造成差错
        if(n % i == 0)
        {
            flag = false;
            break;
        }
    return flag;
}

三、素数筛

考虑这样一个问题,找出区间[1 , n]内的所有素数。
根据我们之前的算法,复杂度为O(n * sqrt(n)),对于n比较小的时候(n < 1e5),可以在1s之内完成,
但是当n比较大的时候,时间复杂度就已经爆炸了,于是素数筛横空出世。

素数筛的基本思想是用素数筛去非素数,也就是如果一个数字不是素数,那么他一定可以是某个素数的整数倍

1、Eratosthenes(埃氏筛法)

bool vis[MAXN];//
int prime[MAXN];//素数表
void prime_table(int n)
{
    int cnt = 0;
    memset(vis,false,sizeof(false));
    for(int i = 2;i <= sqrt(n);i++)
        if(!vis[i])
        {
            //对于一个素数来说,第一个没被筛掉的他的倍数是 i * i 
            //(比 i * i小的数字i * k已被之前的素数作为倍数筛掉)
            for(int j = i * i;j <= n;j += i)//j 有可能会超出int的范围
                vis[j] = true;
            prime[++cnt] = i;
        }
}

2、素数筛

素数筛的方法是对于一个新的数字来说,用已经打好的素数表去判断整除。
每一个素数都只被记录一次,
每一个合数都只会被一个唯一的最小素因子标记一次(例如6只被2标记了,没有被3标记)。
因此是O(n)线性复杂度的。

bool notprime[MAXN];//标记合数
int prime[MAXN],pn,n;//素数表
void init()
{
    pn = 0;//初始化素数表为空
    notprime[1] = true;
    for(int i = 2;i < n;i++)
    {
        if(notprime[i] == false)//找到第一个素数
            prime[pn++] = i;
        for(int j = 0;j < pn && prime[j] * i < n;j++)
        {
            notprime[prime[j] * i] = true;
            if(i % prime[j] == 0)//如果是i的约数,则跳出循环,保证个数字都只被它的最小素因子筛去
                break;
        }
    }
}

四、后续

对于一个比较大的数字来说,判断它是否是素数,一般采用随机素数测试的方法。
以后有时间再写相关的。(感觉给自己挖了很大的坑)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值