线性筛素数
题目
解析
首先,我们有O(nloglogn)的埃式筛:
for(int i=2;i<=n;++i)if(!vis[i])for(int j=i*i;j<=n;j+=i)vis[j]=1;
显然在这题会被卡TLE,原因是存在重复排除,如12会被2和3各筛一次
考虑使用一个数的最小质因数来筛它,这样子就能避免重复
于是我们有了欧拉筛:
for(int i=2;i<=n;i++)
{
if(!ok[i])p[++tot]=i;
for(int j=1;j<=tot&&i*p[j]<=n;j++)
{
ok[i*p[j]]=1;
if(i%p[j]==0)break;
}
}
首先我们用一个数组存下当前筛出的质数,每次筛数时判断是否重复,如果重复就退出
O(n)的证明:
显然将退出时p[j]是i的最小质因数
同时对于1<=k<=j,有p[k]是i×p[k]的最小质因数
对于j<l<=tot,有p[j]是i×p[l]的最小质因数(即从i中分出来的p[j])
于是该代码为线性复杂度
PS:似乎有人拿埃氏筛+bitset过了而且跑得比线性筛快
code:
#include<cstdio>
using namespace std;
int n,q,r,p[6000010],tot=0;
bool ok[100000010];
int main()
{
scanf("%d%d",&n,&q);
for(int i=2;i<=n;i++)
{
if(!ok[i])p[++tot]=i;
for(int j=1;j<=tot&&i*p[j]<=n;j++)
{
ok[i*p[j]]=1;
if(i%p[j]==0)break;
}
}
while(q--)
{
scanf("%d",&r);
printf("%d\n",p[r]);
}
return 0;
}