C - 素数密度

发布时间 2023-03-31 20:57:14作者: xxj112

题解在代码里,如下

点击查看代码
#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
//如果一个数n不是质数,就一定有非一的因数x<=sqrt(n); 
const int N=5e4; //因为所给题目最大到(1<<31) 所以只需要求出来 1~N之间的所有质数就行 
const int M=1e6+7;
int idx=0;
bool prime[N]; 
int p[N], tot;
int ma[M]; //离散化标记 L~R的合数  
void init(){//欧拉筛 
;
    for(int i = 2; i < N; i ++) prime[i] = true;//w++;
    for(int i = 2; i < N; i++){
        if(prime[i]) p[tot ++] = i;
        for(int j = 0; j < tot && i * p[j] < N; j++){
            prime[i * p[j]] = false;// w++;
            if(i % p[j] == 0) break; //w++;
        }
    }
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	init();
	int  ans=0;
	int  l,r,w;
	ma[1]=1; //1 特殊标记 
	cin>>l>>r;
	for(int j=0;j<tot&&p[j]<=sqrt(r);j++) //枚举1~N之间的所有质数 
	{
		 w=(p[j]-l%p[j])%p[j];  //这里的w表示(l+w)%p[j]==0; 
		 if(l+w==p[j])// 这里是l+w刚好等于p[j] ,一倍为质数 
		 w+=p[j]; //所以加一倍 ,为二倍的合数 
		for(long long  i=l+w;i<=r;i+=p[j]) //l+w表示质数p[j]的二倍 ,每次增加一倍 ,把L~R之间所有的p[j] 的倍数标记 
		{
			ma[i%M]=1; //因为所给区间最多为1e6,且递增每次加一,所以modM离散化后,一一对应不会重复 
		}
	}
	for(LL i=l;i<=r;i++) //一一枚举就行 ,这里i开long long ,防止 r=1<<31时 ,再i++ 爆int  
	{
		if(ma[i%M]==0)
		{
			ans++;
		} 
	}
	cout<<ans<<endl;
	return 0;
 }