素数筛
最基础的找素数的方式是从 \(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;
}