【数论】——质数

【数论】——质数

概念

  • 对于一正整数 a,如果 a 的因数有且仅有 1a,则称 a 为质数(素数),否则称 a 为合数。

质数定理

  • 在整个自然数集合中,质数分布相对稀疏,对于一个足够大的数 N[1,N] 中所有的质数个数为:
    C o u n t O f P r i m e s = N ln ⁡ N CountOfPrimes = \frac{N}{\ln N} CountOfPrimes=lnNN

质数的判定

试除法

  • 模版题AcWing 866. 试除法判定质数
    枚举 [2,x] 所有整数,如果 x%i == 0x 不是质数。

  • 优化
    容易发现,合数 x 的因数总是成对出现,并且关于 x \sqrt{x} x 对称,因此只将枚举区间缩小至 [2, x \sqrt{x} x ] 即可,每次判断 x 是否为质数时间复杂度为严格 O( x \sqrt{x} x )

  • 代码

bool is_prime(int x)
{
    if (x <= 1)
        return false;
    /*
         这里建议写 i<=x/i
            原因:
            1)写 sqrt(x),要调用 <cmath> 的函数,太慢、
            2)写 i*i<=x, 如果 i 过大会溢出。
    */
    for (int i = 2; i <= x / i; i++) {if (x % i == 0)
            return false;
    }
    return true;
}

质数的筛选

埃氏筛法

  • 对于任意 x,其倍数 2x,3x… 必然不是质数, 从 2 开始扫描所有小于 N 的数,如果当前数为质数,筛除其小于等于 N 的所有倍数。直到筛去 [1,N] 中的所有质数的倍数,就可以筛去区间内所有合数。

  • 优化:
    由于对于数字 6,会被 2,3 各筛一遍,因此若当前数 x 为质数,小于 x^2 的所有合数已经之前的质数筛去了,只需要筛除 [ x 2 x^2 x2, [ N x \frac{N}{x} xN] ] 的所有 x 的倍数即可。

  • 筛除图解——(来自 李煜东 《算法竞赛进阶指南》)
    在这里插入图片描述

  • 复杂度分析
    每次将 x 的倍数筛除,需要计算:
    c n t = N 2 + N 3 + . . . + N N − 1 + N N cnt=\frac{N}{2}+\frac{N}{3}+...+\frac{N}{N-1}+\frac{N}{N} cnt=2N+3N+...+N1N+NN

c n t = N ( 1 2 + 1 3 + . . . + 1 N − 1 + 1 N ) cnt = N\left(\frac{1}{2}+\frac{1}{3}+...+\frac{1}{N-1}+\frac{1}{N} \right) cnt=N(21+31+...+N11+N1)
此式为 调和级数:
c n t = ln ⁡ N + C cnt = \ln N+{C} cnt=lnN+C
因此复杂度为:O( n ⋅ log ⁡ ( ln ⁡ n ) n\cdot \log \left( \ln n \right) nlog(lnn))

  • 代码
bool st[N]; // 表示是(true)否被筛
int primes[N], cnt = 0; //primes 存储所有质数,cnt 表示当前质数个数
void Eratosthenes(int n)
{for (int i = 2; i <= n; i++) {if (st[i])
            continue;
        primes[++cnt] = i; // 如果没被筛过,就是质数
        for (int j = i; j <= n / i; j++) // 从 x^2 开始筛去 x 的倍数
            st[j * i] = true;
    }
}

线性筛法

  • 上述从 x 2 x^2 x2 开始还是会重复筛除,eg:12 ,被 2,3,6 重复标记,因此需要对产生 12 的方式进行固定,只让其被筛除一次以达到线性复杂度 (O(n))

  • 线性筛法,是将一个数 x,只使 x 被其的最小质因数筛除,eg:12 仅被 2 筛除。

  • 实现方式:
    在埃式筛法的基础上,每次扫描不大于 n i \frac{n}{i} in 的所有质数,将 st[primes[j] * i ] = true 筛除。

  • 筛除图解——(来自 李煜东 《算法竞赛进阶指南》)!
    在这里插入图片描述

  • 代码

bool st[N]; // 表示是(true)否被筛
int primes[N], cnt = 0; //primes 存储所有质数,cnt 表示当前质数个数
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++){if (i % primes[j] == 0) // 如果可以整除,则存在比当前更小的 prime 可以筛去 i,退出
                break;
            st[primes[j] * i] = true; //primes[j] 是 primes[j] * i 的最小质因子
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Siriu_Sky

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值