核心思想:
保证每个合数只会被它的最小质因数筛去,因此每个数只会被标记一次,所以时间复杂度是O(n)
此过程中保证了两点:
- 合数一定被干掉了...
- 每个数都没有被重复地删掉
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#define f(i,a,b) for(register int i=a;i<=b;++i)
#define fd(i,a,b) for(register int i=a;i>=b;--i)
using namespace std;
const int N=10000000+7;
int n,m,f[N],tot;
bool visit[N];
//visit[i]如果被标记了 那么就不是素数
inline int read() {
int data=0,w=1;
char ch=0;
while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
if(ch=='-') w=-1,ch=getchar();
while(ch>='0' && ch<='9') data=data*10+ch-'0',ch=getchar();
return data*w;
}
inline void write(int x) {
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
inline void pd(int Max) {
visit[1]=1;
f(i,2,Max) { //枚举每一个数 顺便枚举倍数
if(!visit[i])//要是没标记到那么就是素数
f[++tot]=i;
for(int j=1; j<=tot && i*f[j]<=Max; j++)
//这里是枚举前面的每一个素数
{
visit[i*f[j]]=1;//把前面的素数倍数都标记上
if(i % f[j]==0) break;//如果不是最小质因子就退出
/****************************
为什么这句话可以忽略掉不是最小质因子 而保证时间复杂度呢
首先 visit[]里面的素数都是严格递增的
如果当前的i含有visit[j] 不妨设 i=visit[j]*k
下一个数 P=i*visit[j+1]肯定可以写成 P=visit[j]*k*visit[j+1]
所以P肯定会在 i=k*visit[j+1] 的时候筛掉
所以这句话可以使得是最小质因子就退出
*****************************/
}
}
}
int main() {
// ios::sync_with_stdio(false);
n=read();
m=read();
pd(n);
f(i,1,m) {
int a=read();
if(visit[a]) puts("No");
else puts("Yes");
}
return 0;
}
代码引自luogu