NOIP 2019提高组模拟--质数(题解)

NOIP提高组–质数

空间限制512MB(这个真的超大
在这里插入图片描述在这里插入图片描述
【题解】一看询问次数这么多足足有1e5;显然就不能用简单的每次询问都去搜一遍。所以很轻易就能想到是要用一下预处理。再看看题目注意关键词质数再看区间范围1e7,很容易就想到用筛法,毕竟一个一个区判断是不是质数复杂度真的太高了(无法接受)。再看看题目有一点两个质数的,熟悉筛法的同学一下子就可以想到这就是埃氏筛(如果不了解的同学可以百度一下);所以我们可以开一个数组zs[]表示质数(鉴于本人英语不好就只能用万能的拼音了),f[]表示需要的数;

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e7+5;
bool f[maxn];//满足条件的数
bool zs[maxn];//质数
int s[maxn];//求和
int idx,l,r;
int main(){
	memset(zs,1,sizeof(zs));
	zs[1]=0;
	f[1]=0;
	for(int i=1;i<=maxn;i++){
		if(zs[i]){/如果是质数
			f[i]=1;
			for(int j=2;j*i<=maxn;j++){
				if(j<=i&&zs[j]){
					f[j*i]=1;//如果是两个质数相乘就满足条件
				}
				zs[j*i]=0;//一定不是质数
			}
		}
		s[i]=s[i-1]+f[i];
	}
	scanf("%d",&idx);
	for(int i=1;i<=idx;i++){
		scanf("%d%d",&l,&r);
		if(f[l])
		printf("%d\n",s[r]-s[l]+1);
		else printf("%d\n",s[r]-s[l]);
	}
	return 0;
}

限于题目中的数据范围,其实不必每次都去跑到1e7,可是记录总的最大右端点做maxn

#include<bits/stdc++.h>
using namespace std;
const int maxn=10000005;
int maxx;
bool f[maxn];
bool zs[maxn];
int s[maxn];
int idx,l[100005],r[100005];
int main(){
	memset(zs,1,sizeof(zs));
	zs[1]=0;
	f[1]=0;
	scanf("%d",&idx);
	for(int i=1;i<=idx;i++){
		scanf("%d%d",&l[i],&r[i]);
		maxx=max(maxx,r[i]);
	}
	for(int i=1;i<=maxx;i++){
		if(zs[i]){
			f[i]=1;
			for(int j=2;j*i<=maxx;j++){
				if(j<=i&&zs[j]){
					f[j*i]=1;
				}
				zs[j*i]=0;
			}
		}
		s[i]=s[i-1]+f[i];
	}
	for(int i=1;i<=idx;i++){
		if(f[l[i]])
		printf("%d\n",s[r[i]]-s[l[i]]+1);
		else printf("%d\n",s[r[i]]-s[l[i]]);
	}
	return 0;
}

用后面这个会快接近三秒;(可能是数据太良心了吧)
在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值