素数筛法,就是在原暴力求解素数代码的基础上,将算法变成线性的。 那么,怎么操作呢??!!
代码:
#include <bits/stdc++.h>
using namespace std;
int n,w,ans[1000010],tot,s;
bool vis[100000010];
int main(){
cin>>n>>w;
for(int i=2;i<=n;i++){
if(vis[i]==false)
ans[++tot]=i;
for(int j=1;j<=tot&&i*ans[j]<=n; j++) {
vis[i*ans[j]]=true;
if(i%ans[j]==0)
break;
}
}
for(int i=1;i<=w;i++){
cin>>s;
int left=1,right=tot,mid;
while(left<=right){
mid=(left+right)/2;
if(s==ans[mid]){
cout<<"Yes"<<endl;
break;
}
else if(s<ans[mid])
right=mid-1;
else
left=mid+1;
}
if(s!=ans[mid])
cout<<"No"<<endl;
}
return 0;
}
这里显然就运用到了筛素数的进一步优化,就是将每一个质数以及它的倍数筛掉,比如说12就可以等于3*4,那么,12就显然不是质数,这样,将所有质数保存在一个数组里,最后只要查找一下就可以了,这真是太棒了!!! 那么,原题的进一步线性优化就是这样的:
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=1000+10,maxm=1000000+10;
int a[maxn],p[maxm],m;
void doing(){
for(int i=2;i<=750;i++)
if(!p[i]){
a[++m]=i;
for(int j=i*i;j<=maxm;j+=i)
p[j]=1;
}
}
int main(){
int x;
doing();
while(1){
cin>>x;
if(x==0)
return 0;
for(int i=2;i<=x/2;i++)
if(p[x-i]==0&&p[i]==0){
cout<<x<<" = "<<i<<" + "<<x-i<<endl;
break;
}
}
return 0;
}
但是,这个程序还不是最优的,因为12既可以等于34也可以等于26,这样岂不是连续算了多遍??!!
那么,我们可以在原代码上进行进一步优化,如果能将重复算的部分删掉就好了,其实,是可以这样的,代码如下:
#include<bits/stdc++.h>
using namespace std;
const int maxn=10000000+5;
int p[maxn],a[maxn];
int main(){
int n,m=0,k;
cin>>n>>k;
for(int i=2;i<=n;i++){
if(!p[i])
a[m++]=i;
for(int j=0;j<m;j++){
if(i*a[j]>n)
break;
p[i*a[j]]=1;
if(i%a[j]==0) //这里是关键,如果能除尽,就说明这个数能被更大的数构成,就直接跳出循环。
break;
}
}
for(int i=1;i<=k;i++){
int s;
cin>>s;
if(s==1){
cout<<"No"<<endl;
continue;
}
if(p[s])
cout<<"No"<<endl;
else
cout<<"Yes"<<endl;
}
return 0;
}