竞赛中我们很多时候会涉及数论的相关知识,说到数论那就不得不提到素数了。下面我就介绍竞赛中常用的筛选素数的方法。
第一种O(sqrt(N))试除法
很简单,就是从素数的定义出发。素数只能被1和它本身整除的数(1除外),那么我们就验证2~sqrt(n)之间是否有i能都整除n即可。特殊的要验证1;
bool check(int n){
for(int i=2;i<=sqrt(n);i++)if(n%i==0)return 0;
return n!=1;
}
第二种就是用线性筛法筛出一个素数表了,O(n)的时间即可完成
线性筛素数如何做到线性,关键就在于它的核心思想。
根据唯一分解定理我们知道任何一个数可以用若干个素数的乘积表示,而线性筛法的核心便是使用每个数最小的那个素因数将其筛去,每个数筛一次,就能做到o(n);
void find(){
for(int i=2;i<=n;i++){
if(!vis[i])p[++cnt]=i; 当前数是素数,那么我们将其储存
for(int j=1;j<=cnt&&p[j]*i<=n;j++){vis[p[j]*i]=1;if(i%p[j]==0)break;}
依次将每个i 与小于它的素数相乘,将得到的数给筛去
特别的,当 i%p[j]==0时退出,为什么呢,因为当前循环中 后续所有的数i*p[k](k>j)都有一个素因子p[j],那么它在后面的循环(当i=i*p[k]时)中自然会被p[j]筛去,如果现在继续筛下去,那么后续又要筛一次,那就不是线性筛了
}
}