Acwing-基础算法课笔记之数学知识(质数)

一、质数

1、概述

在大于1的整数中,如果只包含1和本身这两个约数,就被成为质数,或者叫素数。

二、试除法判定质数

1、过程模拟

判定的方法为试除法

(1)朴素版的试除法判定质数

时间复杂度为 O ( n ) O(n) O(n)
代码如下:

bool is_prime(int n) {
     if (n < 2) return false;
     for (int i = 2; i < n; i ++) {
         if (n % i == 0)
            return false;
     }
     return true;
}

(2)优化版的试除法判定质数

例如:设 d 为被除数,n 为要被判定的数
如果 n%d=0,则 n%(n/d)=0 ,所以只需枚举 d ⩽ \leqslant n/d,所以 d ⩽ \leqslant n \sqrt{n} n
时间复杂度为 O ( n ) O(\sqrt{n}) O(n )
代码如下:

bool is_prime(int n) {
     if (n < 2) return false;
     for (int i = 2; i <= n / i; i ++) {
         if (n % i == 0)
            return false;
     }
     return true;
}

三、试除法分解质因数

代码模板:

void divide(int n) {
	for (int i = 2; i <= n / i; i++) {
		int s = 0;
		if (n % i == 0) {
			while (n % i == 0) {
				n /= i;
				s++;
			}
			printf("%d %d\n", i, s);
		}
	}
	if (n > 1)printf("%d %d\n", n, 1);//只能被其本身整除
	puts("");
}

四、筛质数

1、朴素筛法的过程模拟

23456789101112

⇓ \Downarrow
把2的倍数删掉

23 4 \xcancel{4} 4 5 6 \xcancel{6} 6 7 8 \xcancel{8} 8 9 10 \xcancel{10} 10 11 12 \xcancel{12} 12

⇓ \Downarrow
把3的倍数删掉

23 4 \xcancel{4} 4 5 6 \xcancel{6} 6 7 8 \xcancel{8} 8 9 \xcancel{9} 9 10 \xcancel{10} 10 11 12 \xcancel{12} 12

⇓ \Downarrow
把4的倍数删掉

23 4 \xcancel{4} 4 5 6 \xcancel{6} 6 7 8 \xcancel{8} 8 9 \xcancel{9} 9 10 \xcancel{10} 10 11 12 \xcancel{12} 12

⇓ \Downarrow
把5的倍数删掉

23 4 \xcancel{4} 4 5 6 \xcancel{6} 6 7 8 \xcancel{8} 8 9 \xcancel{9} 9 10 \xcancel{10} 10 11 12 \xcancel{12} 12

⇓ \Downarrow
把6的倍数删掉

23 4 \xcancel{4} 4 5 6 \xcancel{6} 6 7 8 \xcancel{8} 8 9 \xcancel{9} 9 10 \xcancel{10} 10 11 12 \xcancel{12} 12

⇓ \Downarrow
把7的倍数删掉

23 4 \xcancel{4} 4 5 6 \xcancel{6} 6 7 8 \xcancel{8} 8 9 \xcancel{9} 9 10 \xcancel{10} 10 11 12 \xcancel{12} 12

⇓ \Downarrow
把8的倍数删掉

23 4 \xcancel{4} 4 5 6 \xcancel{6} 6 7 8 \xcancel{8} 8 9 \xcancel{9} 9 10 \xcancel{10} 10 11 12 \xcancel{12} 12

⇓ \Downarrow
把9的倍数删掉

23 4 \xcancel{4} 4 5 6 \xcancel{6} 6 7 8 \xcancel{8} 8 9 \xcancel{9} 9 10 \xcancel{10} 10 11 12 \xcancel{12} 12

⇓ \Downarrow
把10的倍数删掉

23 4 \xcancel{4} 4 5 6 \xcancel{6} 6 7 8 \xcancel{8} 8 9 \xcancel{9} 9 10 \xcancel{10} 10 11 12 \xcancel{12} 12

⇓ \Downarrow
把11的倍数删掉

23 4 \xcancel{4} 4 5 6 \xcancel{6} 6 7 8 \xcancel{8} 8 9 \xcancel{9} 9 10 \xcancel{10} 10 11 12 \xcancel{12} 12

⇓ \Downarrow
把12的倍数删掉

23 4 \xcancel{4} 4 5 6 \xcancel{6} 6 7 8 \xcancel{8} 8 9 \xcancel{9} 9 10 \xcancel{10} 10 11 12 \xcancel{12} 12

代码模板:

void get_prime(int n) {
	for (int i = 2; i <= n; i++) {
		if (!st[i])p[cnt++] = n;//如果没有被筛过的条件
		for (int j = i + i; j <= n; j += i)st[j] = true;//将i的倍数筛掉
	}
	printf("%d", cnt);
}

根据上述代码可知:当第一重循环到 i 时,那么第二重循环就会循环 n i \frac{n}{i} in 次,推理公式如下:

n 2 \frac{n}{2} 2n+ n 3 \frac{n}{3} 3n+ ⋯ \dotsb ⋯ \dotsb + n n \frac{n}{n} nn

= n n n ( ( ( 1 2 \frac{1}{2} 21+ 1 3 \frac{1}{3} 31+ ⋯ \dotsb ⋯ \dotsb + 1 n \frac{1}{n} n1 ) ) ) 调和级数 \textcolor{red}{调和级数} 调和级数

所以 lim ⁡ n → ∞ \lim\limits_{n\rarr\infty} nlim ( ( ( 1 2 \frac{1}{2} 21+ 1 3 \frac{1}{3} 31+ ⋯ \dotsb ⋯ \dotsb + 1 n \frac{1}{n} n1 ) ) )

= ln ⁡ n \ln n lnn+ c c c
注意: c 是一个欧拉常数,约等于 0.577 \textcolor{red}{注意:c是一个欧拉常数,约等于0.577} 注意:c是一个欧拉常数,约等于0.577

ln ⁡ n \ln n lnn = log ⁡ e n \log\nolimits_en logen

由于 n log ⁡ e n n\log\nolimits_en nlogen < log ⁡ 2 n \log\nolimits_2n log2n,所以时间复杂度为 O ( n log ⁡ n ) O(n\log n) O(nlogn)

2、埃氏筛法的过程模拟

质数定理: 1 1 1~ n n n 个数中,有 n l n n \frac{n}{lnn} lnnn个质数。

例如以下序列:

23456789101112
p-1p

当前数字 11 11 11 的位置设为 p p p,则前面从小到大的序列为 2 ∼ \sim p-1,所以只要在位置 2 ∼ \sim p-1中的数存在能够被位置 p 的数整除就将其筛掉。

因为 n n n ( ( ( 1 2 \frac{1}{2} 21+ 1 3 \frac{1}{3} 31+ ⋯ \dotsb ⋯ \dotsb + 1 n \frac{1}{n} n1 ) ) )= n ln ⁡ n n\ln n nlnn,所以 n ln ⁡ n ln ⁡ n \frac{n\ln n}{\ln n} lnnnlnn大概会等于 O ( n ) O(n) O(n),但这是一个粗略的估计,是不对的,真实的时间复杂度为 O ( n l o g l o g n ) O(nloglogn) O(nloglogn)(当调和级数只算质数项时)。

例如:
n = 2 32 n=2^{32} n=232 时, l o g n = 32 logn=32 logn=32,则 l o g l o g n = 5 loglogn=5 loglogn=5

代码模板:

void get_prime(int n) {
	for (int i = 2; i <= n; i++) {
		if (!st[i]) {
			p[cnt++] = n;
			for (int j = i + i; j <= n; j += i)st[j] = true;
		}
	}
	printf("%d", cnt);
}

3、线性筛法的过程模拟

∙ \bullet 概述:在筛的时候,从小到大枚举所有的质数,当我们的质数大于 n / i n/i n/i 的时候就跳出循环,即 n % i n\%i n%i = = = 0 0 0时, n % n\% n% ( n / p r i m e s [ j ] ) (n/primes[j]) (n/primes[j]) = = = 0 0 0

代码模板:

void get_prime(int n) {
	for (int i = 2; i <= n; i++) {
		if (!st[i])p[cnt++] = i;
		for (int j = 0; p[j] <= n / i; j++) {//从小到大枚举所有的质数
			st[p[j] * i] = true;//标记不是质数的数
			if (i % p[j] == 0)break;//当p[j]是i的最小质因子,且p[j]是p[j]*i的最小质因子时,退出循环
		}
	}
	printf("%d", cnt);
}

五、总结

1、埃氏筛法

埃氏筛法: O ( n l o g l o g n ) O(nloglogn) O(nloglogn)

2、线性筛法

n只会被它的最小质因子筛掉,分情况讨论如下:
(1)当 i % p [ j ] = 0 i\%p[j]=0 i%p[j]=0 时, p [ j ] p[j] p[j] 一定是 i i i 的最小质因子,且 p [ j ] p[j] p[j] 也一定是 p [ j ] ∗ i p[j]*i p[j]i 的最小质因子;
(2)当 i % p [ j ] ! = 0 i\%p[j]!=0 i%p[j]=0时, p [ j ] p[j] p[j] 一定是小于 i i i 的所有质因子,且 p [ j ] p[j] p[j] 也一定是 p [ j ] ∗ i p[j]*i p[j]i 的最小质因子。

  • 14
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

不会敲代码的狗

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

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

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

打赏作者

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

抵扣说明:

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

余额充值