题意:
求一段区间内的素数的个数
题解:
当区间边界很小时,可以直接根据埃式筛法先预处理所有素数,然后直接暴力遍历计数即可
但当边界太大时,比如求【100000000 100010000】区间内的素数个数,打表是不能达到这个范围的,所以就需要把区间整体转移到【0,10000】
至于如何转移,可以根据埃式筛的原理,素数的倍数一定不是素数,从而把所有的合数给筛出来
筛的方法在代码中
代码:
#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<map>
#include<set>
#include<stack>
//#include<tr1::unordered_map>
#pragma GCC optimize(2)
#define debug cout<<"*"<<endl;
#define input(x) scanf("%d",&x)
#define output(x) printf("%d\n",x)
#define llinput(x) scanf("%lld",&x)
#define lloutput(x) printf("%lld\n",x)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<string,int> psi;
typedef pair<char,char> pcc;
const int mod=1e9+7;
const int INF=1e9+7;
const int maxn=1e6+7;
const double PI=acos(-1);
const int N=4;
/** 一生负气成今日 四海无人对夕阳 **/
ll prime[maxn];
bool vis[maxn];
bool isvis[maxn];
int cot=0;
void pre() //埃式筛素数打表
{
vis[1]=1;
for(ll i=2; i<=maxn; i++)
{
if(!vis[i]) prime[++cot]=i;
for(ll j=1; j<=cot&&i*prime[j]<=maxn; j++)
{
vis[i*prime[j]]=1;
if(i%prime[j]==0) break;
}
}
}
int main()
{
pre();
int t;
cin>>t;
int cas=0;
while(t--)
{
ll a,b;
ll ans=0;
cin>>a>>b;
if(b<=maxn) //对小范围直接遍历计数即可
{
for(ll i=a; i<=b; i++)
{
if(!vis[i]) ans++;
}
}
else
{
memset(isvis,0,sizeof(isvis)); //新的记录数组,来记录【a,b】范围内的是质数还是合数
for(ll i=1; i<=cot; i++)
{
ll k=a/prime[i];
if(prime[i]*k<a) k++;
//其中k*prime[i]是[a,b]内第一个prime[i]的倍数
for(ll j=k*prime[i]; j<=b; j+=prime[i])
{
isvis[j-a]=1; //把所有prime[i]的倍数筛掉
}
}
for(ll i=a; i<=b; i++) //再遍历统计即可
{
if(!isvis[i-a])
ans++;
}
}
cout<<"Case "<<++cas<<": "<<ans<<endl;
}
return 0;
}