错误题目:质数
质数
时间限制:1秒 内存限制:256M
题目描述
小 X 是一位热爱数学的男孩子,在茫茫的数字中,他对质数更有一种独特的情感。小 X 认为,质数是一切自然数起源的地方。
在小 X 的认知里,质数是除了本身和 1 以外,没有其他因数的数字。
但由于小 X 对质数的热爱超乎寻常, 所以小 X 同样喜欢那些虽然不是质数,但却是由两个质数相乘得来的数。
于是,我们定义,一个数是小 X 喜欢的数,当且仅当其是一个质数,或是两个质数的乘积。
而现在,小 X 想要知道,在 L 到 R 之间,有多少数是他喜欢的数呢?
输入描述
第一行输入一个正整数 Q,表示询问的组数。
接下来 Q 行。包含两个正整数 L 和 R。保证 L≤R,L,R <= 10^7 Q <= 10^5
输出描述
输出 Q 行, 每行一个整数, 表示小 X 喜欢的数的个数。
样例
输入
1
1 6
输出
5
思路:乍一看题,似乎很难,但是呢还是有思路的,我看见质数了之后,脑中有三个想法:
- prime判断:把区间中的数遍历一遍(两个数组,输入一个,判断一个),运用判断,标记一下(1代表留下)
- 埃氏筛:先打表,再把区间中的数遍历并判断一遍,然后输出,例如:
1
1 6
打表:
1 | 2 | 3 | 4 | 5 | 6 |
判断:
1 | 2 | 3 | 4 | 5 | 6 |
输出:
2,3,5
- 欧拉筛:确保每个合数只被最小质因数筛掉,每个合数只会被筛到一次。
无语的是三种情况都想到了,可惜当时竟然只尝试了前两种……第三种方法没想到,
现在给大家看一下为什么前两种会pas掉:
- prime判断是需要遍历才能行的,但是我没有看到题目中的数据类型的范围……L,R <= 10^7 Q <= 10^5,这么大,这什么数据类型也装不下啊……
- 埃氏筛:我忽略了一个问题,埃氏筛是由非常严重的超时风险,埃氏筛的时间复杂度为 O(nlogn),故用该方法在处理 1e8 以上的数据时,会有时间超限的风险……
现在我们来看一下正解:
#include<bits/stdc++.h>
using namespace std;
const N=1e7;
int l,r,q,cnt,prine[N];
bool st[N+5],num[N];
void ola(int m) {
for(int i=2; i<=m; i++) {
if(st[i]==0) {
num[i]=1;
prime[cnt++]=i;
}
for(int j=0;j<cnt&&prime[j]*i<=m;j++) {
st[prime[j]*i]=1;
if(st[i]==0) {
num[prime[j]*i]=1;
}
if(i%prime[j]==0) {
break;
}
}
}
}
int main()
int q;
ola(N);
cin>>q;
for(int i=1;i<N;i++){
sum[i]=sum[i-1]+num[i];
}
while(q--){
cin>>l>>r;
cout<<sum[r]-sum[l-1]<<endl;
}
return 0;
}
这道题主要知识点很复杂,最重要的有这几个:
- 1是标记需要输出的;
- 因为它说的是要求区间之内质数和两个质数的乘积,所以还要标记prime[j]*i(15行);
- 当我们看见输入中有:第一行输入一个正整数 Q,表示询问的组数。接下来 Q 行。包含两个正整数 L 和 R。保证 L≤R。L,R <= 10^7 Q <= 10^5类似的时,就能确定要用前缀和(27~29行)
- 注意输出格式!!!题目中说输出 Q 行,每行一个整数,别忘了cout<<sum[r]-sum[l-1];后面加<<endl;