我之前写到过 欧拉筛 埃氏筛 按其复杂度来说 到 1e6是完全可以的,but 如果让你筛选 区间[a,b]的素数(b-a)<=1e6,但a,b最大值为1e11,你怎么办呢.欧拉筛 埃氏筛



首先不要慌 ,一步一步来,a,b最大值为 1e11,但我们知道 用 sqrt(b) 之前的素数 可以筛选1e11的素数

所以我们将 1e6之前的素数 事先打表,然后用这些素数去筛 [a,b]区间内哪些不是素数

但a,b区间太大了,无法开,但b-a<=1e6,所以 我们将区间偏移至 [0,b-a],这样我就可以控制了

外层循环1e6之前的素数,内层用埃氏筛法改进,找到第一个大于a的 且为当前枚举的素数 的倍数的数,然后每次+当前枚举的prime,因为这是prime的倍数,所以他不是素数.(但最少2倍以上,代码中有细节)直接标记就好了 具体怎么区间转移看一下代码就好了:

        for(int i=1;i<=cnt;i++)//外层1e6以内的素数
        {
            ll x=prime[i];
            for(ll k=max(2ll,(n+x-1)/x)*x;k<=m;k+=x)// (n+x-1)/x 是至少为x几倍 注释①
                    other[k-n]=false;
        }

注释①:这个证明详见:证明

然后我们遍历 :

        for(ll i=n;i<=m;i++)
            if(other[i-n]) save[++cnt1]=i;

save里就可以存起来了.

放一道例题叭: POJ 2689 Prime Distance


题目大意:输出a,b区间内,相邻最近的两个素数,与相邻最远的两个素数

题目思路:我们把区间a,b内的素数都找出来,然后遍历一遍差值就可以了

AC:

//#include <bits/stdc++.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define E 2.718
#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
const ll INF=1e9+7;
const int maxn=1e6+8;
const double eps=1e-10;
const ll mod=1000000007;
ll n,m;
ll prime[maxn];
bool vis[maxn];
bool other[maxn];
ll save[maxn];
ll temp[maxn];
ll cnt=0;
void inint()
{
    memset(vis,true,sizeof(vis));
    vis[1]=false;
    for(int i=2;i<50000;i++)
    {
        if(vis[i])
        {
            prime[++cnt]=i;
            for(int k=2*i;k<50000;k+=i)
                vis[k]=false;
        }
    }
}
int main()
{
    inint();
    while(~scanf("%lld%lld",&n,&m))
    {
        ll cnt1=0;
        memset(other,true,sizeof(other));
        if(n==1) other[0]=false;
        for(int i=1;i<=cnt;i++)
        {
            ll x=prime[i];
            for(ll k=max(2ll,(n+x-1)/x)*x;k<=m;k+=x)
                    other[k-n]=false;
        }
        for(ll i=n;i<=m;i++)
            if(other[i-n]) save[++cnt1]=i;
        if(cnt1<=1) printf("There are no adjacent primes.\n");
        else
        {
            for(ll i=2;i<=cnt1;i++)
                temp[i]=save[i]-save[i-1];
            ll maxl=-INF,minl=INF;
            int pos=-1,pos1=-1;
            for(int i=2;i<=cnt1;i++)
            {
                if(temp[i]>maxl)
                {
                    maxl=temp[i];
                    pos=i;
                }
                if(temp[i]<minl)
                {
                    minl=temp[i];
                    pos1=i;
                }
            }
            printf("%lld,%lld are closest, %lld,%lld are most distant.\n",save[pos1-1],save[pos1],save[pos-1],save[pos]);
        }
    }
    return 0;
}

总结:Get New Knowledge !