题目链接
判决素数个数
题目描述
求 X X X, Y Y Y 之间的素数个数(包括 X X X 和 Y Y Y)。
输入格式
两个整数 X X X 和 Y Y Y( 1 ≤ X , Y ≤ 1 0 5 1 \le X,Y \le 10^5 1≤X,Y≤105)。
输出格式
输出一个整数,表示 X , Y X, Y X,Y 之间的素数个数(包括 X X X 和 Y Y Y)。
样例 #1
样例输入 #1
1 100
样例输出 #1
25
题目思路
首先需要提醒的是,本题题面中给出的 1 ≤ X , Y ≤ 1 0 5 1 \le X,Y \le 10^5 1≤X,Y≤105 是误导项。根据实际提交的代码,当使用埃筛法求素数时,如果数组最大开到 1 0 5 10^5 105时是无法通过 测试样例 # 3的。我把数组大小开到 1 0 6 10^6 106后成功AC。
这题的关键就是在判断素数,好在本题没有在时间上限制,所以采用何种方法去判断素数都可以AC。
试除法素数判断
C++代码如下
int check(int n)
{
if (n < 2)
return 0;
for (int i = 2; i <= sqrt(n); ++i)
{
if (n % i == 0)
return 0;
}
return 1;
}
2 2 2 之前的都是非素数,从 2 2 2 开始,如果有除自己本身以外其他因子的数,都是合数(非素数)。 而我们并不用判断到 n − 1 n - 1 n−1 ,因为一个数在小于 自己本身 开根号 sqrt(n) 一侧没有因子的情况下,在大于 sqrt(n) 也不会存在因子。
埃筛法
C++代码如下
// 埃筛法
int ans = 0;
vector<bool> isPrime(1000001);
isPrime[0] = true;
isPrime[1] = true;
for (int i = 2; i <= y; ++i)
{
if (!isPrime[i])
{
// 从 x 开始计数
if (i >= x)
ans++;
for (int j = i * 2; j <= y; j += i)
{
isPrime[j] = true;
}
}
}
printf("%d", ans);
这里可以一次性筛选出
y
y
y 范围内的所有素数,其中用false
表示是素数,用true
表示不是素数。这样的做法与网上其他埃筛法初始化可能存在一点不同,因为考虑到,创建一个bool
型数组,它的默认值全为false
,而想把数组全部初始为true
还需要花费一些时间,比如使用memset
方法,或vector
数组的resize
方法。
埃筛法的理念,主要在于,当我们找到一个素数时,那么这个素数的
2
2
2 倍、
3
3
3 倍…就都不可能是素数。
本题还有一处需要注意,题目中并没有明确说明 x x x 与 y y y 哪个更大,所以在进行素数判断前需要找出其中最大的一个
完整代码
试除法质数判断
#include <bits/stdc++.h>
using namespace std;
int check(int n)
{
if (n < 2)
return 0;
for (int i = 2; i <= sqrt(n); ++i)
{
if (n % i == 0)
return 0;
}
return 1;
}
int main()
{
int x, y;
scanf("%d%d", &x, &y);
if (x > y)
swap(x, y);
// 普通判断
int sum = 0;
for (int i = x; i <= y; ++i)
{
if (check(i))
++sum;
}
printf("%d", sum);
return 0;
}
埃筛法
#include <bits/stdc++.h>
using namespace std;
int main()
{
int x, y;
scanf("%d%d", &x, &y);
if (x > y)
swap(x, y);
// 埃筛
int ans = 0;
vector<bool> isPrime(1000001);
isPrime[0] = true;
isPrime[1] = true;
for (int i = 2; i <= y; ++i)
{
if (!isPrime[i])
{
if (i >= x)
ans++;
for (int j = i * 2; j <= y; j += i)
{
isPrime[j] = true;
}
}
}
printf("%d", ans);
return 0;
}