题意:
给定两个整数L和U,你需要在闭区间[L,U]内找到距离最接近的两个相邻质数C1和C2(即C2-C1是最小的),如果存在相同距离的其他相邻质数对,则输出第一对。
同时,你还需要找到距离最远的两个相邻质数D1和D2(即D1-D2是最大的),如果存在相同距离的其他相邻质数对,则输出第一对。
输入格式
每行输入两个整数L和U,其中L和U的差值不会超过1000000。
输出格式
对于每个L和U ,输出一个结果,结果占一行。
结果包括距离最近的相邻质数对和距离最远的相邻质数对。(具体格式参照样例)
如果L和U之间不存在质数对,则输出“There are no adjacent primes.”。
数据范围
1 ≤ L < U ≤ 2 31 − 1 1≤L1≤L<U≤231−1
输入样例:
2 17
14 17
输出样例:
2,3 are closest, 7,11 are most distant.
There are no adjacent primes.
分析:
要 求 区 间 [ L , R ] 内 , 距 离 最 近 的 两 个 相 邻 质 数 和 距 离 最 远 的 两 个 相 邻 质 数 。 要求区间[L,R]内,距离最近的两个相邻质数和距离最远的两个相邻质数。 要求区间[L,R]内,距离最近的两个相邻质数和距离最远的两个相邻质数。
思 路 上 , 先 筛 出 这 段 区 间 内 的 质 数 , 再 遍 历 一 遍 求 相 邻 质 数 差 值 的 最 值 。 思路上,先筛出这段区间内的质数,再遍历一遍求相邻质数差值的最值。 思路上,先筛出这段区间内的质数,再遍历一遍求相邻质数差值的最值。
难点:
线 性 筛 是 筛 [ 1 , N ] 内 的 质 数 , L 和 R 的 范 围 将 达 到 1 0 9 , 无 论 是 从 时 间 上 还 是 空 间 上 考 虑 均 不 合 理 。 线性筛是筛[1,N]内的质数,L和R的范围将达到10^9,无论是从时间上还是空间上考虑均不合理。 线性筛是筛[1,N]内的质数,L和R的范围将达到109,无论是从时间上还是空间上考虑均不合理。
但 是 , 区 间 的 长 度 不 超 过 1 0 6 , 但是,区间的长度不超过10^6, 但是,区间的长度不超过106,
对 于 每 个 合 数 X , 都 必 存 在 一 个 最 小 质 因 子 P , 对 应 的 还 有 另 一 个 因 子 X P , 对于每个合数X,都必存在一个最小质因子P,对应的还有另一个因子\frac{X}{P}, 对于每个合数X,都必存在一个最小质因子P,对应的还有另一个因子PX,
而 X 的 最 小 质 因 子 P , 必 有 P ≤ X , 而X的最小质因子P,必有P≤\sqrt{X}, 而X的最小质因子P,必有P≤X,
所 以 , 我 们 可 以 先 筛 出 R 以 内 的 质 数 的 P i , 再 借 助 埃 氏 筛 法 的 思 想 , 筛 去 区 间 [ L , R ] 内 P i 的 倍 数 。 所以,我们可以先筛出\sqrt{R}以内的质数的P_i,再借助埃氏筛法的思想,筛去区间[L,R]内P_i的倍数。 所以,我们可以先筛出R以内的质数的Pi,再借助埃氏筛法的思想,筛去区间[L,R]内Pi的倍数。
由 于 质 数 的 范 围 较 大 , 可 以 将 区 间 [ L , R ] 内 的 质 数 先 减 去 偏 移 量 L , 映 射 到 区 间 [ 0 , R − L ] 内 , 用 布 尔 数 组 标 记 。 由于质数的范围较大,可以将区间[L,R]内的质数先减去偏移量L,映射到区间[0,R-L]内,用布尔数组标记。 由于质数的范围较大,可以将区间[L,R]内的质数先减去偏移量L,映射到区间[0,R−L]内,用布尔数组标记。
细节:
埃 式 筛 法 : 对 每 一 个 质 数 P i , 筛 去 [ L , R ] 内 P i 的 倍 数 。 埃式筛法:对每一个质数P_i,筛去[L,R]内P_i的倍数。 埃式筛法:对每一个质数Pi,筛去[L,R]内Pi的倍数。
如 何 计 算 出 第 一 个 大 于 等 于 L 的 P i 的 倍 数 ? 如何计算出第一个大于等于L的P_i的倍数? 如何计算出第一个大于等于L的Pi的倍数?
将 P i 扩 大 ⌈ L P i ⌉ 倍 , 且 至 少 两 倍 , 将P_i扩大\lceil\frac{L}{P_i}\rceil倍,且至少两倍, 将Pi扩大⌈PiL⌉倍,且至少两倍,
而 ⌈ L P i ⌉ = ⌊ L + P i − 1 P i ⌋ , 而\lceil\frac{L}{P_i}\rceil=\lfloor\frac{L+P_i-1}{P_i}\rfloor, 而⌈PiL⌉=⌊PiL+Pi−1⌋,
故 对 于 每 一 个 P i , 从 m a x ( 2 P i , ⌊ L + P i − 1 P i ⌋ ) 开 始 , 筛 掉 P i 的 倍 数 。 故对于每一个P_i,从max(2P_i,\lfloor\frac{L+P_i-1}{P_i}\rfloor)开始,筛掉P_i的倍数。 故对于每一个Pi,从max(2Pi,⌊PiL+Pi−1⌋)开始,筛掉Pi的倍数。
时间复杂度分析:
线 性 筛 : 筛 出 R 以 内 的 质 数 , R 上 限 约 为 2.1 × 1 0 9 , 故 我 们 筛 出 50000 以 内 的 质 数 即 可 。 线性筛:筛出\sqrt{R}以内的质数,R上限约为2.1×10^9,故我们筛出50000以内的质数即可。 线性筛:筛出R以内的质数,R上限约为2.1×109,故我们筛出50000以内的质数即可。
埃 式 筛 : 筛 出 区 间 长 度 不 超 过 1 0 6 内 的 质 数 , 计 算 次 数 为 1 0 6 ( 1 2 + 1 3 + 1 5 + 1 7 + . . . ) , 时 间 复 杂 度 O ( n l o g ( l o g n ) ) 埃式筛:筛出区间长度不超过10^6内的质数,计算次数为10^6(\frac{1}{2}+\frac{1}{3}+\frac{1}{5}+\frac{1}{7}+...),时间复杂度O(nlog(logn)) 埃式筛:筛出区间长度不超过106内的质数,计算次数为106(21+31+51+71+...),时间复杂度O(nlog(logn))
当 n = 1 0 6 时 , l o g ( l o g n ) ≈ 5 , 最 终 的 时 间 复 杂 度 是 O ( n ) 级 别 的 。 当n=10^6时,log(logn)≈5,最终的时间复杂度是O(n)级别的。 当n=106时,log(logn)≈5,最终的时间复杂度是O(n)级别的。
代码:
#include
#include
#include
#define ll long long
using namespace std;
const int N=1e6+10;
int primes[50000],cnt;
bool st[N];
void get_prime(int n,int L,int R) //二次筛法,筛出[L,R]内的质数
{
memset(st,false,sizeof st);
cnt=0;
for(int i=2;i<=n;i++) //预处理出[2,50000]内的质数,50000是大于sqrt(R)上界的一个数
{
if(!st[i]) primes[cnt++]=i;
for(int j=0;primes[j]*i<=n;j++)
{
st[primes[j]*i]=true;
if(i%primes[j]==0) break;
}
}
memset(st,false,sizeof st);
for(int i=0;i<cnt;i++)
{
ll p=primes[i];
ll start=max(2*p, (L+p-1)/p*p);
for(ll j=start;j<=R;j+=p)
st[j-L]=true;
}
cnt=0;
for(int i=0;i<=R-L;i++)
if(!st[i] && i+L>=2)
primes[cnt++]=i+L;
}
int main()
{
int l,r;
while(~scanf("%d%d",&l,&r))
{
get_prime(50000,l,r);
if(cnt<2) puts("There are no adjacent primes.");
else
{
int maxp=0,minp=0;
int maxd=0,mind=1e6;
for(int i=0;i+1<cnt;i++)
{
int d=primes[i+1]-primes[i];
if(d>maxd) maxd=d, maxp=i;
if(d<mind) mind=d, minp=i;
}
printf("%d,%d are closest, %d,%d are most distant.\n",
primes[minp],primes[minp+1],primes[maxp],primes[maxp+1]);
}
}
return 0;
}