题目描述
The branch of mathematics called number theory is about properties of numbers. One of the areas that has captured the interest of number theoreticians for thousands of years is the question of primality. A prime number is a number that is has no proper factors (it is only evenly divisible by 1 and itself). The first prime numbers are 2,3,5,7 but they quickly become less frequent. One of the interesting questions is how dense they are in various ranges. Adjacent primes are two numbers that are both primes, but there are no other prime numbers between the adjacent primes. For example, 2,3 are the only adjacent primes that are also adjacent numbers.
Your program is given 2 numbers: L and U (1<=L< U<=2,147,483,647), and you are to find the two adjacent primes C1 and C2 (L<=C1< C2<=U) that are closest (i.e. C2-C1 is the minimum). If there are other pairs that are the same distance apart, use the first pair. You are also to find the two adjacent primes D1 and D2 (L<=D1< D2<=U) where D1 and D2 are as distant from each other as possible (again choosing the first pair if there is a tie).输入格式
Each line of input will contain two positive integers, L and U, with L < U. The difference between L and U will not exceed 1,000,000.
输出格式
For each L and U, the output will either be the statement that there are no adjacent primes (because there are less than two primes between the two given numbers) or a line giving the two pairs of adjacent primes.
输入样例
2 17
14 17
输出样例2,3 are closest, 7,11 are most distant.
There are no adjacent primes.
参考思路
题目大意是给定区间范围,分别找到两个距离最小和距离最大的素数。
我们用素数筛的话开不了这么大的数组,但题目暗示我们区间范围是不超过1000000的。那么我们可以
- 筛出1-50000中的所有质数,并且对合数打上标记.
- 在L-R的范围用我们已求出的质数筛出其中的合数(设p为质数,则i*p一定不为质数),并对其打上标记
- 遍历L-R,没有打标记的元素即为我们所求的素数,然后存进另一个数组里即可。具体操作看代码。
参考代码
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<memory>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 50;
ll l, r;
ll prime[maxn], cnt;
ll vis[maxn];//标记数组
ll p[maxn];//区间素数
void Gprime(ll n)//线性筛素数
{
for (int i = 2; i <= n; ++i)
{
if (!vis[i])prime[++cnt] = i;
for (int j = 1; i * prime[j] <= n && j <= cnt; j++)
{
vis[i * prime[j]] = 1;//标记合数
if (i % prime[j] == 0) break;
}
}
}
int main()
{
Gprime(50050);//筛出根号R内的所有质数以及剩下的合数
while (scanf("%lld%lld", &l, &r)!=EOF)
{
l = l == 1 ? 2 : l;//特判L=1的情况
memset(vis, 0, sizeof(vis));//重置标记数组,等下用来筛L R的素数
for (ll i = 1; i <= cnt; ++i)//枚举已经筛出来的质数
{
ll p = prime[i];
ll start;
//我们从大于L的最小的能被p整除的数开始,因为有可能会在接下来筛的过程中把自己也一起筛掉,所以在此特判一下
if ((l + p - 1) / p * p > 2 * p)
start = (l + p - 1) / p * p;
else
start = 2 * p;
for (ll j = start; j <= r; j += p)
vis[j - l + 1] = 1;//因为如果从j开始标记的话可能会爆vis的空间,所以我们这里从1开始标记合数,类似滚动数组
}
ll count = 0;
for (ll i = l; i <= r; ++i) //p为范围内素数 i要long long
{
if (!vis[i - l + 1])
p[++count] = i;
}
if (count < 2)
cout << "There are no adjacent primes.\n";
else
{
ll m1 = p[1], m2 = p[2], n1 = p[1], n2 = p[2];
for (ll i = 3; i <= count; ++i)
{
if (p[i] - p[i - 1] < m2 - m1)
m2 = p[i], m1 = p[i - 1];
if (p[i] - p[i - 1] > n2 - n1)
n2 = p[i], n1 = p[i - 1];
}
printf("%lld,%lld are closest, %lld,%lld are most distant.\n", m1, m2, n1, n2);
}
}
return 0;
}
昨夜雨疏风骤