题目来源:http://acm.hit.edu.cn/hoj/problem/view?id=2276
Count prime
Submitted : 741, Accepted : 177
Given an integer interval [L, R](L <= R <= 2147483647, R - L <= 1000000), please calculate the number of prime(s) in the interval.
Input
Multiple cases.
There is one line in each case, which contains two integer: L, R.
Output
There is only one line for each case, which contains the number of prime(s) in the interval.
Sample Input
2 11
Sample Output
5
分析:
1:在[1,50000]范围内筛素数,因为[1,2147483647]范围内的合数的质因子肯定在[1,50000]范围内,再由此范围的素数淘汰掉以此素数为质因数的合数即可。
在[1,50000]范围内 筛选素数, 采用 优化的 线性筛选法。
=1 , 表示 i+L 这个数是 合数。 即 i -> i +L , 可以把数很大的区间 , 转换成 数比较小的区间。
3:题目 数据较大 , 因此用 typedef long long LL
4: 分类: Max_N=50005 > sqrt(2147483647)
1) :L < R < Max_N 质子数为 dp[R] - dp[L].
2);L <= Max_N <R [L ,R ]== [L , Max_N] + [Max_N +1 , R] 质子数为 dp[Max_N] - dp[L] + [Max_N , R]
3):Max_N<L < R , 此时 我们需要用到 下标平移。
对于[L,R] , 我们用【1,50005】内得到的质因子, 淘汰掉以此素数为质因数的合数即可。
for p=(2,3,5.....)
start 为以p 为 质因数的 大于L的 最小的数。
for(start , start + p, start +2p, .....) , 这些全是 以p 为质因子的合数。故筛掉 。 visited[start ,...] =1 .
代码如下:
#include<iostream>
#include<stdlib.h>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<string>
#include<queue>
#include<algorithm>
#include<map>
#define Max 1000005
#define Max_N 50000
using namespace std;
typedef long long LL;
LL visited[Max]; // visited[i] = 1 表示 i+L 是 合数,下标平移
int PrimeNum;
LL prime[Max_N] ; // 记录 prime[0]=2 ,prime[1]=3
int IsNotPrime[Max_N]; // IsNotPrime[i]=1 表示i 是合数
int dp[Max_N]; // dp[i] = num; 表示 i + L 的 质数个数为 num
// 最优化的线性筛素数法
void make_prime()
{
PrimeNum=0;
memset(IsNotPrime , 0 , sizeof(IsNotPrime)); // 开始都是素数
dp[0]=dp[1]=0;
for(int i=2 ; i<=Max_N ; i++)
{
if(!IsNotPrime[i]) prime[PrimeNum++]=i;
for(int j=0 ; j<PrimeNum && i*prime[j]<=Max_N; j++)
{
IsNotPrime[i* prime[j]]=1;
if(i%prime[j] == 0)
break;
}
dp[i]=PrimeNum;
}
}
LL Ans(LL l, LL r)
{
if(r<Max_N)
return dp[r]-dp[l-1];
LL ans=0;
memset(visited, 0 ,sizeof(visited));
if(l <= Max_N)
{
ans+=dp[Max_N]- dp[l-1];
l=Max_N +1;
}
for(LL i=0 ; prime[i] *prime[i] <=r; i++ )
{
LL start=(l/prime[i] ) *prime[i];
if(start< l ) start +=prime[i];
for(LL j=start ; j<=r ; j+=prime[i])
visited[j-l]=1;
}
for(LL i=0 ; i<=r-l ;i++)
ans+=!visited[i];
return ans;
}
int main()
{
make_prime();
LL l,r;
while(cin>>l>>r)
{
printf("%d\n",Ans(l,r));
}
return 0;
}