洛谷P1835-素数密度

素数密度

题目描述

给定区间 [L,R]1LR<231RL106),请计算区间中素数的个数。

输入格式

第一行,两个正整数 LR

输出格式

一行,一个整数,表示区间中素数的个数。

样例 #1

样例输入 #1

2 11

样例输出 #1

5

L,R本身太大,不可能直接线性筛[L,R]的素数,但是RL106,从这方面入手
有一个定理是说一个合数x的最大质因子px(因为如果一个合数,它的最小质因子如果大于自身的平方,那么该最小质因子与这个数的其他质因子相乘,就是两个大于自身平方根的数相乘肯定就大于自身了,这与两个质因子相乘应该小于等于自身矛盾),所以我们可以筛出[2,50000]的素数,然后根据这些素数用埃氏筛法筛掉[L,R]的合数即可(R最大2147483647,开平方后小于50000,所以[2,2147483647]内的合数都可以被[2,50000]中的质数,通过质数的倍数来筛掉)
注意:
特判L=1的情况(因为筛法是从2开始筛的)
R如果为2147483647的话,循环的时候j+=pri[i]大于R会爆int,所以j要用long long
L,R,start要用long long,因为L如果为2147483647的话,计算第一个大于等于L的 pri[i]的倍数(2倍起) 这个合数的时候会爆int
注意scanf用%lld读入L,R

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=5e4+5, MAX=1e6+5;
//----------------------------
int pri[MAXN], vis[MAXN];
bool book[MAX];
void init()
{
	for(int i=2; i<MAXN; i++){
		if(!vis[i])pri[++pri[0]]=i;
		for(int j=1; j<=pri[0] && i*pri[j]<MAXN; j++){
			vis[i*pri[j]]=1;
			if(i%pri[j]==0)break;
		}
	}
	return;
}
int main(void)
{
	ll L, R, ans=0;
	scanf("%lld%lld", &L, &R); //注意这里要写%lld,不然读进来的L,R数值不对 
	init();
	if(L==1)book[0]=1; //筛法只能筛出[2, x]的合数,L=1时,需要特判 
	for(int i=1; i<=pri[0]; i++){
		ll start;
		if(pri[i]>=L){
			start=2*pri[i];
		}else{
			if(L%pri[i]==0){
				start=L;
			}else{
				start=(L/pri[i]+1)*pri[i];
			}
		}
		//上面这些,是为了在L~R区间中,从第一个大于等于L的pri[i]的倍数(2倍起)开始筛合数 
		for(ll j=start; j<=R; j+=pri[i]){ //这里的j要用 long long,因为如果R=2147483647的话,那么j+=pri[i]后大于R的话,如果j还是int就爆成负数了,那么接下来book[j-L]就segmentation fault了 
			book[j-L]=1; //压缩一下空间 
		}
	}
	for(int i=0; i<R-L+1; i++){
		if(book[i]==false)
			ans++;
	}
	printf("%d\n", ans);
	return 0;
} 
posted @   YianSanren  阅读(153)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示