🎬 博主名称 :个人主页
⛺️心简单,世界就简单

序言
今天讲一下质数的内容,下面是目录可以看看
目录😍质数
😁优化
😁优化
😍筛质数
😁思想
质数
定义:在大于1的整数中,只含有1和自身这两个约数,就被称为质数
质数的判定
试除法(暴力)
这个是最暴力的写法,时间复杂度是o( n )
cppbool is_prime(int n){ if(n < 2) return false; for(int i = 2; i < n; i ++){ if(n % 2 == 0) return false; } return true; }优化
如果d | n(| 这个是整除符号,就是如果d能整除n),那么(n/d) | n,比如12,如果2是12的约数,那6也是,3是12的约数,那4也是,所以我们发现他们都是成对存在的。那我们枚举时候,是不是就可以只枚举那一对里较小的一个,也就是d <= n/d,也就是d^2 <= n,也就是d <= sqrt(n),我们就吧时间1优化到了o(sqrt(n)).
我们的写法也很多,比如循环时候写 i <= sqrt(n),这个我们每次循环都要调用,时间比较慢,还有的会写 i * i < n,这个如果我们的 i * i超过了int 范围就会变成负数,我们最终就写i <= n / i,这个就不会超出范围了,
cppbool is_prime(int n){ if(n < 2) return false; for(int i = 2; i <= n / i; i ++){ if(n % 2 == 0) return false; } return true; }
分解质因数
试除法(暴力)
我们小时候正常写法,可能就是从小到大开始一直枚举所有数
cppvoid get_prime(int n){ for(int i = 2; i <= n; i++){ if(n % i == 0){ int s =0 ; while(n % i == 0){ n/=i; s ++; } printf("%d %d\n", i, s); } } }优化
我们的循环条件是可以变一下的,我们知道n中最多只包含一个大于sqrt(n)的质因子 ,所以我们枚举时候可以先把小于sqrt(n)的质因子枚举出来,然后最后判断n是不是 > 1,是的话就说明n就是那个大于sqrt(n)的质因子了,这里需要注意的是n是不断在变化的,这里n虽然不断在变化但也不会影响这个算法的正确性,可以拿 n = 34试试
cppvoid get_prime(int n){ for(int i = 2; i <= n / i; i++){ if(n % i == 0){ int s =0 ; while(n % i == 0){ n/=i; s ++; } printf("%d %d\n", i, s); } } if(n > 1) printf("%d %d\n",n , 1); puts(""); }
筛质数
思想
我们基本思想是这样筛的,先写出一串数2 3 4 5 6 7 8 9 10 11 12 ......我们把每个数的倍数都删掉,我们先看2,那我们就把2的倍数都删掉,然后再看3再把3的倍数都删掉........
对于一个P来说,如果他没有被删掉,那就说明从2~P-1里都没有把他删掉,说明P不是2~P-1里任何一个数的倍数,那就说明2~P-1里没有任何一个数是P的约数,那他就是一个质数
最朴素算法
时间复杂度大约是这个o(nlogn),因为计算上稍微繁琐,就不写时间复杂度怎么算的了,可以自己问问ai
cppvoid get_prime(int n){ for(int i = 2; i <= n; i++){ if(!st[i]){ primes[cnt ++] = i; } } for(int j = i + i; j <= n; j += i) st[j] = true; }
稍微优化算法---埃氏筛
我们可以把下面那个循环放入 if 里,我们只需要把质数的倍数给筛掉就行
时间复杂度是o(nloglogn)
cppvoid get_prime(int n){ for(int i = 2; i <= n; i++){ if(!st[i]){ primes[cnt ++] = i; for(int j = i + i; j <= n; j += i) st[j] = true; } } }
线性筛(欧拉筛)
这个基本思路也差不多,就是把每个合数用它的某一个质因子把他筛掉就行
他的思想有两种情况
1, i % primes[ j ] == 0. primes[ j ]一定是 i 的最小质因子,primes[ j ]一定是primes[ j ] * i 的最小质因子
2,i % primes[ j ] != 0. primes[ j ]一定小于 i 的最小质因子,primes[ j ]一定是primes[ j ] * i的最小质因子
核心思想:每个合数只被它的最小质因子筛掉一次
st[primes[ j ] * i] = true ; 这个就是核心思想
每个合数
x都可以表示为:
x = 最小质因子 × 某个数 在欧拉筛中:primes[j] 是质数i 是当前遍历的数primes[j] × i 就是要标记的合数关键:通过控制 i和 primes[j] 的组合,确保每个合数只被它的最小质因子标记一次然后为了防止出现重复,如果(i % primes[j] == 0)我们就break就行
还有就是循环条件
我们要标记的合数是
primes[j] × i,必须满足:primes[j] × i ≤ n变形得到 primes[j] ≤ n / i
cppconst int N = 1e6 +10; int primes[N], cnt; bool st[N]; void get_prime(int n){ for(int i = 2; i <= n; i++){ if(!st[i]) primes[cnt ++] = i; for(int j = 0; primes[j] <= n / i; j ++){ st[primes[j] * i] = true; if(i % primes[j] == 0) break; } } }
完结下一章讲约数,给个三连吧,谢谢了
