Help Hanzo
题目
T组数据,每组数据给出a,b两个值,让求a<=x<=b中有多少个x是质数
分析
可以发现此题的a,b可以到2e9的范围,所以想要把这么大的范围质数筛选完是不可能的,筛质数有个常用的做法就是筛出sqrt(N)的质数,然后再用这些质数去筛后面的质数。
所以我们先把2~2^16范围的质数筛选出来,我们对其之后的合数进行质因数分解 其中必定有一个质数是在2~2^16中,否则这个数一定是大于
的,并不在
范围内。
所以,我们可以用前预筛选出来的质数(大概6000个),去对a,b区间去掉合数,这里因为a,b可能非常大,所以我们把[a,b]映射到[0,b-a]。
如果我们可以直接在前6000个质数看有多少个质数落在这个区间
所以总到时间复杂度:
2s一般是可以过的
AC代码
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <cstring>
#include <unordered_map>
#include <unordered_set>
using namespace std;
typedef long long ll;
const ll maxn = (1LL<<16)+10;
ll T,A,B;
bool vis[maxn],vis2[100010];
ll P[100010],tail;
void init(){
for(int i = 2;i<maxn;i++){
if(!vis[i]){
P[tail++] = i;
for(ll j = (ll)i*i;j<maxn;j+=i){
vis[j] = true;
}
}
}
}
ll test(ll a ,ll b){ //用于对拍
ll cnt = 0;
for(ll i = a;i<=b;i++){
int tag = 1;
for(ll j = 2;j*j<=i;j++){
if(i%j ==0) {
tag = 0;
break;
}
}
if(tag) cnt++;
}
return cnt;
}
ll solve(ll a,ll b){
ll cnt = 0;
if(b<maxn){
for(int i = 0;i<tail;i++){
if(P[i]>=a && P[i]<=b) cnt++;
if(P[i]>b) break;
}
}else{
memset(vis2,0,sizeof vis2);
for(ll i = 0;i<tail;i++){
for(ll j = (a+P[i]-1)/P[i];j<=b/P[i];j++){
if(j == 1 || j == 0) continue;//质数的0倍,1倍不是合数,需要跳过
vis2[P[i]*j-a] = true;
}
}
for(ll i = 0;i<=b-a;i++){
if(!vis2[i]) cnt++;
}
}
return cnt;
}
int main(){
init();
cin>>T;
int kase = 0;
while(T--){
scanf("%lld %lld",&A,&B);
if(A==1) A = 2; //这个最好改成2
printf("Case %d: %lld\n",++kase,solve(A,B));
}
return 0;
} 
京公网安备 11010502036488号