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.
题意:给你一个区间,要求出这个区间内相距最大和相距最小的相邻素数。
思路:由于l,r的范围太大,不能直接打表找出所有的素数。但是题目所给的l,r相差不超过1e6,所有我们可以先打表找出小的素数,然后再用小的素数去筛出这个区间内的合数。l,r不超过2,147,483,647,所以预处理的时候只要找出50000范围内的素数就足够了。
那么如何利用小素数筛除区间内的合数呢?假设区间为[100,200],我们已经知道了20以内的所有素数,从第一个素数2开始筛除,那么依次筛除100,102,104...,因此我们发现,只要从L/2倍开始一直到R/2结束就可以筛除这个区间内所有是2的倍数的合数了。
综上,需要用两重循环,第一重枚举所有50000以内的素数,第二重枚举倍数(从L/p[i]到R/p[i]),将所有合数用数组标记一下。需要注意的是,数组不能开2,147,483,647这么大,所以要加一个偏移量。
//
// main.cpp
// C
//
// Created by zyh on 15/8/5.
// Copyright (c) 2015年 zyh. All rights reserved.
//
#include <iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<queue>
#include<stack>
using namespace std;
int a[1000005],p[50005]; //a数组用于标记,p数组记录50000以内素数
int cnt;
void init() //预处理出50000以内素数
{
memset(a,0,sizeof(a));
int m=(int)sqrt(5005+0.5);
for(int i=2;i<=m;i++)
{
if(a[i]==0)
{
for(int j=i*i;j<50005;j+=i)
{
a[j]=1;
}
}
}
cnt=0; //cnt为50000以内素数的个数
for(int i=2;i<50005;i++)
{
if(a[i]==0)
{
p[cnt++]=i;
}
}
}
int main()
{
init();
int l,r;
while(scanf("%d%d",&l,&r)!=EOF)
{
memset(a,0,sizeof(a));
if(l==1) l=2; //注意l=1的时候需要特判一下,否则会出问题
for(int i=0;i<cnt;i++)
{
int k=(l-1)/p[i]+1;
int b=r/p[i]; //注意这里不能直接写成for(int j=k; j*p[i]<=r; j++),因为如果j*p[i]可能会爆longlong,先开始我这样写结果RE了
for(int j=k;j<=b;j++)
{
if(j>1) //j不等于1的时候才能筛除,否则就把p[i]当做合数筛除了
a[j*p[i]-l]=1;
}
}
int imax=-1,imin=1e9,maxl=0,maxr=0,minl=0,minr=0;
int temp=-1;
for(int i=0;i<=r-l;i++) //我之前写成for(int i=l; i<=r; i++)然后直接判断a[i-l]结果不知道为啥一直RE。。。
{
if(a[i]==0)
{
if(temp!=-1)
{
if(imax<(i-temp))
{
imax=i-temp;
maxl=temp+l;
maxr=i+l;
}
if(imin>(i-temp))
{
imin=i-temp;
minl=temp+l;
minr=i+l;
}
temp=i;
}
else
{
temp=i;
}
}
}
if(imax==-1) printf("There are no adjacent primes.\n");
else
{
printf("%d,%d are closest, %d,%d are most distant.\n",minl,minr,maxl,maxr);
}
}
return 0;
}
这道题我各种RE。。。最终总结还是因为2,147,483,647这个数字太狗逼了。。。危险的边缘。。恩。。
大素数的筛法也是经过子韬学长的提示【羞羞脸】以及自己的一番思索才明白的。。。然后被告知学霸给我们讲课的时候已经教过了,然而我因为睡过头而没有听到233333
总之学习到新的姿势还是要及时整理一下的,恩。