POJ2689_Prime Distance【素数】【两次筛法】

Prime Distance

Time Limit: 1000MS
Memory Limit: 65536K

Total Submissions: 12644
Accepted: 3369

Description

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).

Input

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.

Output

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.

Sample Input

2 17

14 17

Sample Output

2,3 are closest, 7,11 are most distant.

There are no adjacent primes.

Source

Waterloo local 1998.10.17

题目大意:给你一个区间【L,U】,求出从L到U之间素数序列中,连续两个素数差值最大

的最小的两对素数对,但其中(1<=L< U<=2,147,483,647),但区间【L,U】距离不超

过1000000

思路:因为L,U的值太大了,普通素性判断和素数筛法都不可行,所以可以考虑先筛选

一次,筛出50000以内的素数,然后用50000以内的素数再次筛选出区间【L,U】的素

数。第一次素数筛法比较简单,主要是第二次筛法,分别判断【L,U】中每个数是50000

以内的素数的多少倍,若为1倍,则从2倍开始筛选。若不为1倍,则考虑是否是整数倍,

若为整数倍,则从整数倍开始筛,否则从下1倍开始筛选

比如【L,U】为【50000,60000】,则50000为2的250000倍,应从2的25000倍筛选,

也就是50000,50002,50004,50006……筛去。

若【L,U】为【50001,60000】,则50001不为2的整数倍,应从2的250001倍筛选,也

就是50002,50004,50006……筛去。

参考博文:http://blog.csdn.net/returnzero__/article/details/7835655

#include<stdio.h>
#include<string.h>
bool Prime[50010];
int Primer[1000010];
bool Prime1[1000010];
int IsPrime()//第一次筛50000内的素数
{
    int num = 0;
    for(int i = 2; i <= 50000; i++)
        Prime[i] = true;
    for(int i = 2; i <= 50000; i++)
    {
        if(Prime[i])
        {
            Primer[num++] = i;
            for(int j = i+i; j <= 50000; j+=i)
            {
                Prime[j] = false;
            }
        }
    }
    return num;
    //num为50000范围内的素数个数
}

int solve(__int64 a,__int64 b)
/*
在第一次筛素数的基础上,利用50000以内的素数,筛去范围【a,b】之间的素数倍数,
剩下则为素数
*/
{
    int num = IsPrime();
    memset(Prime1,true,sizeof(Prime1));//Prime1数组用来存放范围【a,b】的素性判断

    if(a == 1)//这里注意1不是素数
        Prime1[0] = 0; //这里表示0+1不为素数

    for(__int64 i = 0; i < num && Primer[i] * Primer[i] <= b; i++)
    {
        __int64 begin = a/Primer[i] + (a%Primer[i] != 0);
        //上边的a/Primer算出应a为素数Primer[i]的多少倍
        //(a%Primer[i]!=0)表示应从Primer[i]的a/Primer[i]倍开始筛,还是a/Primer[i]+1倍筛
        if(begin == 1)//若得出结果为所被筛素数的1倍,则从该素数的2倍开始筛
            begin++;

        for(begin = begin*Primer[i]; begin <= b; begin += Primer[i])
            Prime1[begin - a] = false;
    }

    //这里重新利用Primer数组,用来存放区间【a,b】间的素数,num为素数个数
    memset(Primer,0,sizeof(Primer));
    num = 0;
    for(__int64 i = a; i <= b; i++)
    {
        if(Prime1[i-a]==1)
        {
            Primer[num++] = i-a;
        }
    }
    return num;
}

int main()
{
    __int64 a,b;

    __int64 posa1,posb1,posa2,posb2;
    while(~scanf("%I64d%I64d",&a,&b))
    {
        __int64 Max = -2147483647,Min = 2147483647;
        int num = solve(a,b);
//        for(__int64 i = 0; i < num; i++)
//            printf("%I64d ",Primer[i]+a);
        if(num <= 1)
        {
            printf("There are no adjacent primes.\n");
            continue;
        }
        for(int i = 0; i < num-1; i++)//这里i+1范围为1到num-1,则i范围为0到num-2,之前一直错在这里
        {
            if(Primer[i+1]-Primer[i] < Min)
            {
                Min = Primer[i+1] - Primer[i];
                posa1 = Primer[i];
                posb1 = Primer[i+1];
            }
            if(Primer[i+1]-Primer[i] > Max)
            {
                Max = Primer[i+1] - Primer[i];
                posa2 = Primer[i];
                posb2 = Primer[i+1];
            }
        }

        printf("%I64d,%I64d are closest, %I64d,%I64d are most distant.\n",posa1+a,posb1+a,posa2+a,posb2+a);
    }
    return 0;
}
时间: 2024-11-03 03:47:03

POJ2689_Prime Distance【素数】【两次筛法】的相关文章

POJ 2689 Prime Distance 素数筛选法应用

题目来源:POJ 2689 Prime Distance 题意:给出一个区间L R 区间内的距离最远和最近的2个素数 并且是相邻的 R-L <= 1000000 但是L和R会很大 思路:一般素数筛选法是拿一个素数 然后它的2倍3倍4倍...都不是 然后这题可以直接从2的L/2倍开始它的L/2+1倍L/2+2倍...都不是素数 首先筛选出一些素数 然后在以这些素数为基础 在L-R上在筛一次因为 R-L <= 1000000 可以左移开一个1百万的数组 #include <cstdio>

【数学】【数论】素数的线性筛法

写在前面 记录了个人的学习过程,同时方便复习 素数的线性筛法 有时候需要筛出来一张素数表,即1~n范围内的所有素数 一个个枚举判断是否为素数显然太慢 于是经过仔细的研究之后,发现如果存在正整数k(k>2)不是素数,那么它的因子里面一定包含之前的素数 这样的话,开一个boolean数组标记一下不是素数的数,筛到它们的时候跳过就好 详见埃拉托斯特尼筛法 但是如果这样筛,显然会有重复的筛除啊 比如6筛去了42,7也筛去了42 这样的情况还有很多很多,十分影响效率,时间上并不是线性的 但如果按照一个数的

POJ-2689 Prime Distance (两重筛素数,区间平移)

Prime Distance Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 13961   Accepted: 3725 Description The branch of mathematics called number theory is about properties of numbers. One of the areas that has captured the interest of number th

数论快速入门(同余、扩展欧几里德、中国剩余定理、大素数测定和整数分解、素数三种筛法、欧拉函数以及各种模板)

数学渣渣愉快的玩了一把数论,来总结一下几种常用的算法入门,不过鶸也是刚刚入门, 所以也只是粗略的记录下原理,贴下模板,以及入门题目(感受下模板怎么用的) (PS:文中蓝色字体都可以点进去查看百度原文) 附赠数论入门训练专题:点我打开专题(题目顺序基本正常,用以配套数论入门) 一.同余定理 简单粗暴的说就是:若 a-b == m 那么 a%m == b%m 这个模运算性质一眼看出...直接上入门水题: Reduced ID Numbers 附AC代码(这个也没啥模板....知道就好) #inclu

leetcode 161. One Edit Distance 判断两个字符串是否是一步变换 --------- java

Given two strings S and T, determine if they are both one edit distance apart. 给定两个字符串,判断他们是否是一步变换得到的. 在这里需要注意几点: 1.不等于1的变换都要返回false(包括变换次数等于0). 2.还有很多细节需要注意. 方法如下: 1.直接判断:1)如果差值大于1,直接返回false.  2)如果长度相同,那么依次判断,是否只有一个字母不一样.  3)如果不一样,那么看是否是只是多出了一个字母. p

一般筛法求素数+快速线性筛法求素数

素数总是一个比较常涉及到的内容,掌握求素数的方法是一项基本功. 基本原则就是题目如果只需要判断少量数字是否为素数,直接枚举因子2 ..N^(0.5) ,看看能否整除N. 如果需要判断的次数较多,则先用下面介绍的办法预处理. 一般的线性筛法 首先先介绍一般的线性筛法求素数 void make_prime() { memset(prime, 1, sizeof(prime)); prime[0]=false; prime[1]=false; int N=31700; for (int i=2; i<

【转载】一般筛法求素数+快速线性筛法求素数

素数总是一个比较常涉及到的内容,掌握求素数的方法是一项基本功. 基本原则就是题目如果只需要判断少量数字是否为素数,直接枚举因子2 ..N^(0.5) ,看看能否整除N. 如果需要判断的次数较多,则先用下面介绍的办法预处理. 一般的线性筛法 首先先介绍一般的线性筛法求素数 void make_prime() { memset(prime, 1, sizeof(prime)); prime[0]=false; prime[1]=false; int N=31700; for (int i=2; i<

素数的一般筛法和快速线性筛法

一般筛法: 1 void prime() { 2 memset(vis, true, sizeof(vis)); 3 vis[0] = vis[1] = false; 4 for (int i = 2; i < maxn; i++) { 5 for (int j = 2; i * j < maxn; j++) { 6 vis[i * j] = false; 7 } 8 } 9 } 快速线性筛法: 1 int prime[N] = {0}: 2 bool isNotPrime[N] = {1,

[洛谷P3383]线性筛素数-欧拉筛法

Description 如题,给定一个范围N,你需要处理M个某数字是否为质数的询问(每个数字均在范围1-N内) Input&Output Input 第一行包含两个正整数N.M,分别表示查询的范围和查询的个数. 接下来M行每行包含一个不小于1且不大于N的整数,即询问该数是否为质数. Output 输出包含M行,每行为Yes或No,即依次为每一个询问的结果. Solution 代码如下: #include<iostream> #include<cstring> using n