题目大意
解题思路
埃式筛法的复杂度是 O ( n l o g l o g n ) O(nloglogn) O(nloglogn)的。但是此题的范围是 1 0 12 10^{12} 1012因此不能使用埃式筛法。并且空间复杂度也不允许。但是我们可以借鉴埃式筛法的思想,它根据两个事实;
- (1) b b b以内的合数的最小质因数一定不超过 b \sqrt b b。即 x ∈ [ a , b ) x \in [a,b) x∈[a,b)且 x x x是合数,因此其必有质因数小于 b \sqrt b b
- (2) 做出 [ 2 , b ) [2,\sqrt b) [2,b)的质数表,并从 [ a , b ) [a,b) [a,b)中划去所有质数倍数,剩下的就是质数。
因此为了解此题,我们需要维护一个
- i s _ p r i m e 1 [ i ] is\_prime1[i] is_prime1[i]:用来判断 i ∈ [ 2 , b ) i \in [2,\sqrt b) i∈[2,b)范围内的数是否是素数。
由于数字太大,为了节省空间。我们维护一个
- i s _ p r i m e 2 [ i − a ] is\_prime2[i-a] is_prime2[i−a]: 来判断 i ∈ [ a , b ) i \in[a, b) i∈[a,b)是否是素数.
代码
#include<iostream>
using namespace std;
typedef long long ll;
const int MAXN = 1000000+5;
ll is_prime1[MAXN];
ll is_prime2[MAXN];
void get_primes(ll a, ll b)
{
// ------------初始化 --------------
for(ll i=0; i*i<b; i++)
is_prime1[i] = 1;
is_prime1[0] = is_prime1[1] = 0;
for(ll i=a; i<b; i++)
is_prime2[i-a] = 1;
// ---------------------------------
for(ll i=2; i*i<b; i++)
{
if(is_prime1[i])
{
// 筛is_primes1
for(ll j=(ll)2*i; j*j<b; j+=i)
is_prime1[j] = 0;
// 筛is_primes2
for(ll j=(ll)(a-1+i)/i*i; j<b; j+=i)
is_prime2[j-a] = 0;
}
}
}
int main()
{
ll a, b;
cin >> a >> b;
get_primes(a, b);
ll ans = 0;
for(ll i=a; i<b; i++)
{
if(is_prime2[i-a])
ans++;
}
cout << ans << endl;
}
知识点
- 上方的代码中有这么一行
j = (ll)(a-1+i)/i*i
。 ( a − 1 + i ) / i (a-1+i)/i (a−1+i)/i是对 a / i a/i a/i向上取整,因此此计算的作用是求得第一个 > = a >=a >=a的 i i i的倍数。