题目大意

求区间[L, R]中距离最大和最小的两对相邻质数。R<2^31, R-L<1e6。

总体思路

本题数据很大。求sqrt(R)的所有质数,用这些质数乘以j, j+1, j+2...k(j和k使得积属于[L,R])筛选出[L,R]中的合数,然后在[L,R]的质数中得到所求。

筛法求质数

为在O(n)的时间复杂度中求得质数,我们要使筛选时每个可能为质数的数只访问一次。我们用v[i]表示i的最小质因数。每次循环到i时,假设v[i]和小于i的质数都已经在前面求出来了,若v[i]==0,则i是个质数。然后对于每个不大于v[i]的已知质数p,令v[i*p]=p。

不漏

证明:若i+1是个合数,则在处理i+1以前v[i+1]便已知。i+1必然可以化为若干个质数的积,记此质数的集合为P其中最小的质数为a,剩余质数的积为x。显然a<=x<=i。i之前循环到x时,a必然存在于已经求出的质数集合当中(因为a<=x),且a不大于v[x](因为a是P中最小的)。所以一定能由a*x得到i+1。

不重

证明:如果不要求p<=v[i],则值p*i会重复计算若v[i]<=p<=i,则在i循环之前必会循环到p,那个时候就把v[i]*p给算了。

注意

  • 本题中质数是从2开始的。
  • [L,R]质数中找所求时,避免1的出现,不能直接改循环初始条件。
  • 筛选合数时,j至少为2,否则素数乘以1还是素数,我们却把它设成合数了。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdarg>
#include <algorithm>
using namespace std; const int INF = 0x3f3f3f3f, MAX_RANGE = 1000010, MAX_SQRT_N = 1 << 16;
#define LOOP(i, n) for(int i=0; i<n; i++)
#define LoopFrom(i, l, r) for(int i=l; i<r; i++)
#define LoopDown(i, n) for(int i=n-1; i>=0; i--) int GetPrime(int *ans, int n)
{
static int v[MAX_SQRT_N];
memset(v, 0, sizeof(v));
int ansCnt = 0;
LoopFrom(i, 2, n + 1)
{
if (!v[i])
{
ans[ansCnt++] = i;
v[i] = i;
}
for (int j = 0; j < ansCnt && ans[j] <= v[i] && ans[j] <= n/i; j++)
v[ans[j] * i] = ans[j];
}
return ansCnt;
} void Proceed(int l, int r)
{
static int a[MAX_SQRT_N];
static bool IsPrime[MAX_RANGE];
memset(a, 0, sizeof(a));
memset(IsPrime, false, sizeof(IsPrime));
LOOP(i, r - l + 1)
IsPrime[i] = true;
int len = GetPrime(a, sqrt((double)r)+0.5);
LOOP(i, len)
LoopFrom(j, max((l / a[i])*a[i] < l ? l / a[i] + 1 : l / a[i], 2), r / a[i] + 1)
IsPrime[a[i] * j - l] = false;
int minDist = INF, maxDist = 0, prev = -1;
int c1=0, c2=INF, d1=0, d2=-INF;
LoopFrom(i, 0, r - l + 1)
{
if (IsPrime[i] && i+l>1)
{
if (prev == -1)
{
prev = i;
continue;
}
if (i - prev < c2 - c1)
{
c1 = prev;
c2 = i;
}
if (i - prev > d2 - d1)
{
d1 = prev;
d2 = i;
}
prev = i;
}
}
if (c2 == INF)
printf("There are no adjacent primes.\n");
else
printf("%d,%d are closest, %d,%d are most distant.\n", c1+l, c2+l, d1+l, d2+l);
} int main()
{
int l, r;
while (~scanf("%d%d", &l, &r))
Proceed(l, r);
return 0;
}

筛法求质数2

void GetPrime(int *prime, int n)
{
static bool NotPrime[MAX_N];
memset(NotPrime,false,sizeof(NotPrime));
int primeCnt=0;
for(int i=2; i<=n; j++)
{
if(!NotPrime[i])
prime[primeCnt++]=i;
for(int j=0; j<primeCnt; j++)
{
if(i*prime[j]>N)
break;
NotPrime[i*prime[j]]=true;
if(i%prime[j]==0)
break;
}
}
} 

不重

原则:对于一个数n都由它的最小质因数p和某一个数i相乘得到。

n的最小质因数只有1个,所以n只被访问了一次。

不漏

证明:对于n=p*i,p是n的最小质因数,当外层循环到当前i时,p一定会在循环j时被访问到。

因为n的质因数集合包含i的质因数集合,所以p小于等于i的最小质因数,而循环到当前i时,所有小于i的质数都求出来了,包含着i的最小质因数,故命题成立。

POJ2689 Prime Distance 质数筛选的更多相关文章

  1. POJ2689 - Prime Distance(素数筛选)

    题目大意 给定两个数L和U,要求你求出在区间[L, U] 内所有素数中,相邻两个素数差值最小的两个素数C1和C2以及相邻两个素数差值最大的两个素数D1和D2,并且L-U<1,000,000 题解 ...

  2. POJ2689 Prime Distance(数论:素数筛选模板)

    题目链接:传送门 题目: Prime Distance Time Limit: 1000MS Memory Limit: 65536K Total Submissions: Accepted: Des ...

  3. ZOJ 1842 Prime Distance(素数筛选法2次使用)

    Prime Distance Time Limit: 2 Seconds      Memory Limit: 65536 KB The branch of mathematics called nu ...

  4. 解题报告:poj2689 Prime Distance

    2017-10-03 11:29:20 writer:pprp 来源:kuangbin模板 从已经筛选好的素数中筛选出规定区间的素数 /* *prime DIstance *给出一个区间[L,U],找 ...

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

    Prime Distance Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 13961   Accepted: 3725 D ...

  6. POJ-2689 Prime Distance,区间素数筛法

                                                    Prime Distance 只会埃氏筛法的弱鸡今天读了读挑战程序设计120页,明白了求小区间内素数的方 ...

  7. poj 2689 Prime Distance(区间筛选素数)

    Prime Distance Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9944   Accepted: 2677 De ...

  8. poj2689 Prime Distance题解报告

    题目戳这里 [题目大意] 给定一个区间[L,R],求区间内的质数相邻两个距离最大和最小的. [思路分析] 其实很简单呀,很明显可以看出来是数论题,有关于质数的知识. 要注意一下的就是L和R的数据范围都 ...

  9. POJ2689:Prime Distance(大数区间素数筛)

    The branch of mathematics called number theory is about properties of numbers. One of the areas that ...

随机推荐

  1. Go中的main函数和init函数

    Go里面有两个保留的函数:init函数(能够应用于所有的package)和main函数(只能应用于package main).这两个函数在定义时不能有任何的参数和返回值.虽然一个package里面可以 ...

  2. GitHub上fork别人打代码后如何保持和原作者同步的更新

    1.进入你的GitHub发起Pull  request 2.选择compare across  forks 3.反向操作.base fork改为自己的,head fork改为原作者的 4.点击 cre ...

  3. C# 查找、结束进程 - 通过进程名精确、模糊查找、结束进程

    /// <summary> /// 根据“精确进程名”结束进程 /// </summary> /// <param name="strProcName" ...

  4. SmartUpload实现文件上传

    (一)SmartUpload组件简介 SmartUpload组件 专门用于实现文件上传及下载的免费组件   (二)SmartUpload组件特点 使用简单:编写少量代码,完成上传下载功能 能够控制上传 ...

  5. java程序员级别划分

    IT路虽好,却难走.1级   为会基本语法 大学里的JAVA教程 能及格 2级   自己可以写个 俄罗斯方块,扫雷,贪吃蛇, 拼图之类的小游戏 3级   能够进手机游戏CP,SP公司,做手机游戏 或者 ...

  6. mssql for VSCode Guide

    前言 mssql 出自微软自己的 Visual Studio Code 开源插件,代码托管于 GitHub 上. 不过需要注意的一点是,使用 insert into 语句新增的数据...中文是会乱码的 ...

  7. window 8 电脑操作服务集合(网址)

    如何开启Win8远程桌面 http://jingyan.baidu.com/album/48206aeae06627216ad6b3bf.html?picindex=2 Win8.1用户账户的配置管理 ...

  8. git与pycharm结合使用

    一.配置pycharm 在pycharm中选择file-->setting,在弹出的窗口中选择version control,选择git,配置git的路径 将当前项目关闭 在弹出的窗口中选择ch ...

  9. Coreldraw软件反盗版提示x8有优惠活动 cdr x8提示盗版怎么办?

    CorelDRAW X8装不上,我的悲伤有这么大,或者比这还大一点...♥♥♥如果你遇到这样的断了网,卸了装,装了卸,然后再安装的...╮(-_-)╭这样的保存和另存为都点不了,不敢关电脑的亦或是这样 ...

  10. 数据库连接池c3p0

    XML配置文件: <?xml version="1.0" encoding="UTF-8"?> <c3p0-config> <!- ...