素数筛
最基础的找素数的方式是从 \(2\) 到 \(x-1\) 全除一遍,后来变成除到 \(\sqrt{x}\) 就行辽(因为因数是成对出现的)。
既然判一个数要 \(O(n)\) 不如一边把小于 \(n\) 的数全判了。
就出现了筛法。
首先是埃筛(埃拉特斯托尼筛法)由于 素数唯一分解定理 ,我们只要记录下到目前数为止的质数,再把目前数的质数倍数标记为非素数。然而这还不是线性。一个数会筛其质因子个数次。
上面没什么用的,直接从这里开始也行。
最终出现了线性筛。
大体和埃筛相同,但是在标记非负数时,一旦目前数可以被记录的质数整除就跳到下一个质数。意思就是只会标记一个数小于最小质因子的质数倍数。
关于准确性:
\[
\bf 对于一个数 \;\mit x\;\bf可表示为\;\mit s\times p_{min}\;\bf 即最小质因子的整数倍。\\
如果我们要筛\;\mit s\times p_{min}\times p_x\quad (p_x>p_{min})\;\bf 就会和 \;\mit s\times p_{x}\times p_{min}\;\bf 筛重。
\]
其实就是 \(p\) 的乘的顺序不同但是都会被筛上,只要我们给其定一个排列规律,即为只会乘比现在最小质因子小的质数,就保证了 \(p\) 是从大到小排列的,一个序列只会出现一次。
这样所有的数就会且只会筛一次。
\(\frak code\)
#include<cstdio> #include<algorithm> using namespace std; typedef int int_; #define int long long int n,tot; int inp[3000050]; int prime[3000050]; int_ main() { scanf("%lld",&n); inp[1]=inp[0]=1; for(int i=2;i<=n;i++){ if(!inp[i]){ prime[++tot]=i; } for(int j=1;j<=tot && prime[j]*i<=n;j++){ int tp=prime[j]*i; inp[tp]=1; if(i%prime[j] == 0) break; } } for(int i=1;i<=tot;i++){ printf("%lld ",prime[i]); } return 0; }