首先明确任何合数都能表示成一系列素数的积
第一种易于理解的方法:
注意对1的预处理即可,空间较大
var
n,m,x,t :longint;
i,j :longint;
prime :array[0..10000010] of longint;
vis :array[0..10000010] of boolean;
begin
read(n,m);t:=0;
vis[1]:=true;
for i:=2 to n do
begin
if not vis[i] then
begin
inc(t);
prime[t]:=i;
end;
for j:=1 to t do
if (i*prime[j]>n) then break else
begin
vis[i*prime[j]]:=true;
if (i mod prime[j]=0) then break;
end;
end;
for i:=1 to m do
begin
read(x);
if vis[x] then writeln('No') else writeln('Yes');
end;
end.
另一种时空效率都不错的方法,不太容易理解:
var
half,t,n,m,x,k :longint;
prime :array[0..5000010] of boolean;
i,j :longint;
begin
read(n,m);
half:=n div 2;t:=trunc(sqrt(n));
for i:=0 to half do prime[i]:=true;
for i:=0 to t do
if prime[i] then
begin
k:=i+i+3;
j:=k*i+i+k;
while (j<=half) do
begin
prime[j]:=false;
inc(j,k);
end;
end;
for i:=1 to m do
begin
read(x);
if (x=2) then writeln('Yes') else
if (x mod 2=0) then writeln('No') else
if prime[(x-3) div 2] then writeln('Yes') else writeln('No');
end;
end.
简单解释一下:
首先偶数除了2其他全都是合数所以特判一下2其他的偶数全都不考虑
那么我们只考虑奇数,那么我们就只剩下half个数字
由于1不是质数,那么从3开始考虑
对于prime数组,表示的数和下标对应的关系
表示的数:3 5 7 9 11 13 15
下标: 0 1 2 3 4 5 6
显然,可以得到,对于prime[i]表示的数为2*i+3(i=0,1,2,3......half)
那么,数字的范围即trunc(sqrt(n))
举个例子,3是质数,那么我们就要把3*3,3*5,3*7...置成false,它们对应的下标为3、6、 9....
一般化,即:
如果prime[i]为质数,
令k=2*i+3,那么prime[j]=false ( j=k*i+k+i*l*k(l=0,1,2,....) )
——by Eirlys