一.质数的判定
枚举$2~sqrt{n}$,判断能否被整除.
1和0既不是质数也不是合数.
二.质数的筛选
1.朴素筛法
朴素筛法就是枚举1~n,分别判断他们是不是素数.
复杂度O($ sum_{i=2}^n sqrt{i} $).
几乎用不到.
2.Eratosthenes筛法
找到一个质数,把这个质数的倍数都筛去.
void prework(){ for(int i=2;i<=n;++i){ if(!vis[i]){ p[++p[0]]=i; for(int j=i*i;j<=n;j+=i) vis[j]=1; } } }
这里从i*i开始就行了,因为$ j imes i(j<i) $ 会被之前j的$ i $倍筛掉.
时间复杂度是O(nlogloogn),效率非常接近线性.
比较容易记忆,不易写错,用埃筛的思想还可以做这道题https://www.cnblogs.com/huihao/p/11742014.html
3.线性筛法(欧拉筛)
Eratosthenes筛法会重复标记合数,比如12会被2,3标记.也就是筛去12的方式不唯一,导致每个合数筛去的次数可能不止一遍,导致算法不是线性,在数据接近极限的时候Eratosthenes筛法可能会超时.
线筛对于每一个合数只会被他的最小值质因子筛去,每个数的最小质因子唯一可确保每个质数只会被筛去一次.
还是埃筛的思路,把质数的倍数标记为合数.但在找到质数时,并不着急筛去他的倍数.
埃筛的内层是倍数,线筛的外层是倍数. 素数$ p[j] $的$ i $倍. p[j]<=i;
也就是说 p[j]*i全是合数,要筛去,但又得保证p[j]是他的最小值质因子, 由于p[j]是递增的 当 i%p[j]==0 是 p[j] 就一定是i的最小质因子此时 p[j + 1]就 一定大于i的最小质因子,也就是说 p[j+1] * i 的最小质因子不是p[j + 1],所以当i%p[j]==0时就可以跳出循环.
那这样能保证每个合数都被筛到吗?
考虑合数 x. 设他的最小质因子为 i . 令 j=x/i; 则 x=i*j; 由i的性质可知 i<j, 且i小于j的最小质因子.
当外层循环到 j 时,由于 i 小于 j 的最小质因子,所以肯定会被 i*j 筛掉.
void get_prime(){ for(int i=2;i<=n;++i){ if(!vis[i]) p[++p[0]]=i; for(int j=1;j<=p[0]&&1LL*i*p[j]<=n;++j){ vis[i*p[j]]=1; if(i%p[j]==0) break; } } }
留坑..
三.质因数分解
我懒....