【区间素数筛】 Help Hanzo

题意:

        求一段区间内的素数的个数


题解:

        当区间边界很小时,可以直接根据埃式筛法先预处理所有素数,然后直接暴力遍历计数即可

 

         但当边界太大时,比如求【100000000 100010000】区间内的素数个数,打表是不能达到这个范围的,所以就需要把区间整体转移到【0,10000】

          至于如何转移,可以根据埃式筛的原理,素数的倍数一定不是素数,从而把所有的合数给筛出来

         

          筛的方法在代码中


代码:

#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<map>
#include<set>
#include<stack>
//#include<tr1::unordered_map>
#pragma GCC optimize(2)
#define debug cout<<"*"<<endl;
#define input(x) scanf("%d",&x)
#define output(x) printf("%d\n",x)
#define llinput(x) scanf("%lld",&x)
#define lloutput(x) printf("%lld\n",x)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<string,int> psi;
typedef pair<char,char> pcc;
const int mod=1e9+7;
const int INF=1e9+7;
const int maxn=1e6+7;
const double PI=acos(-1);
const int N=4;

/**  一生负气成今日    四海无人对夕阳   **/

ll prime[maxn];
bool vis[maxn];
bool isvis[maxn];
int cot=0;
void pre()    //埃式筛素数打表
{
    vis[1]=1;
    for(ll i=2; i<=maxn; i++)
    {
        if(!vis[i]) prime[++cot]=i;
        for(ll j=1; j<=cot&&i*prime[j]<=maxn; j++)
        {
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)   break;
        }
    }
}
int main()
{
    pre();
    int t;
    cin>>t;
    int cas=0;
    while(t--)
    {
        ll a,b;
        ll ans=0;
        cin>>a>>b;
        if(b<=maxn)    //对小范围直接遍历计数即可
        {
            for(ll i=a; i<=b; i++)
            {
                if(!vis[i]) ans++;
            }
        }
        else
        {
            memset(isvis,0,sizeof(isvis));    //新的记录数组,来记录【a,b】范围内的是质数还是合数
            for(ll i=1; i<=cot; i++)
            {
                ll k=a/prime[i];    
                if(prime[i]*k<a) k++;
                //其中k*prime[i]是[a,b]内第一个prime[i]的倍数
                for(ll j=k*prime[i]; j<=b; j+=prime[i])
                {
                    isvis[j-a]=1;    //把所有prime[i]的倍数筛掉
                }
            }
            for(ll i=a; i<=b; i++)    //再遍历统计即可
            {
                if(!isvis[i-a])
                    ans++;
            }
        }
        cout<<"Case "<<++cas<<": "<<ans<<endl;
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值