LightOJ 1197 Help Hanzo(区间素数筛选)

Help Hanzo

Amakusa, the evil spiritual leader has captured the beautiful princess Nakururu. The reason behind this is he had a little problem with Hanzo Hattori, the best ninja and the love of Nakururu. After hearing the news Hanzo got extremely angry. But he is clever and smart, so, he kept himself cool and made a plan to face Amakusa.

Before reaching Amakusa’s castle, Hanzo has to pass some territories. The territories are numbered as a, a+1, a+2, a+3 … b. But not all the territories are safe for Hanzo because there can be other fighters waiting for him. Actually he is not afraid of them, but as he is facing Amakusa, he has to save his stamina as much as possible.

He calculated that the territories which are primes are safe for him. Now given a and b he needs to know how many territories are safe for him. But he is busy with other plans, so he hired you to solve this small problem!

Input
Input starts with an integer T (≤ 200), denoting the number of test cases.

Each case contains a line containing two integers a and b (1 ≤ a ≤ b < 231, b - a ≤ 100000).

Output
For each case, print the case number and the number of safe territories.

Sample Input
3
2 36
3 73
3 11
Sample Output
Case 1: 11
Case 2: 20
Case 3: 4
Note
A number is said to be prime if it is divisible by exactly two different integers. So, first few primes are 2, 3, 5, 7, 11, 13, 17, …

题意:
求a~b区间素数的数量。(1 ≤ a ≤ b < 2^31, b - a ≤ 100000).
思路:
由于a,b的取值范围太大,无法将这个区间内的所有素数全部略举出来,但b-a这个范围相对小了很多。
我们需要通过打表找到 [2,sqtr(b)]之间的素数,就可以把埃氏筛法运用到【a,b】之间,
素数。
代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn= 1e5+10;
#define ll long long
bool prime1[maxn],prime2[maxn];
ll i,j;
int sieve(ll a,ll b)
{
    for(i=0;i*i<=b;i++)
        prime1[i]=0;
    for(i=0;i<=b-a;i++)
        prime2[i]=1;
    for(i=2;i*i<=b;i++)
    {
        if(prime1[i]==0)
        {
            for(j=i+i;j*j<=b;j+=i)
                prime1[j]=1;
            for(j=max(2ll,(a+i-1)/i)*i;j<=b;j+=i)
                prime2[j-a]=0;//这里的2LL是2的长整型数,与2LL比较的意思就是j最小是i的两倍
                                 //(a+i-1)/i表示的是[a,b]区间内的第一个数至少为i的多少倍.
        }
    }
    int sum=0;
    for(int i=0;i<=b-a;i++)
        if(prime2[i])sum++;
    return sum;
}
int main()
{
    ll a,b;
    int t;
    int ans=1;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld%lld",&a,&b);
        int res=sieve(a,b);
        if(a==1)res--;//因为上面函数初始化的时候把所有的数都定义为素数,后来经过for循环
                       // 4,6,8....等数都成了false,但是1还是true,所以当a等于1的时候,
                         // 要减去1

        printf("Case %d: %d\n",ans++,res);
    }
    return 0;
}

埃氏筛法:
原理其实很简单,首先将2到n范围内的整数写下来,其中2是最小的素数。将表中所有的2的倍数划去,表中剩下的最小的数字就是3,他不能被更小的数整除,所以3是素数。再将表中所有的3的倍数划去……以此类推,如果表中剩余的最小的数是m,那么m就是素数。然后将表中所有m的倍数划去,像这样反复操作,就能依次枚举n以内的素数,这样的时间复杂度是O(nloglogn)。
在这里插入图片描述
这个里面还有一个小技巧,就是加入我们知道了当前的质数,我们要怎么知道下一个质数。我们可以发现,加入我们标记了当前质数的所有比它大的倍数之后我们从当前质数开始往下枚举,遇到第一个没有被标记的数就是下一个质数了。
原因:
因为往后找第一个没有标记过的数说明了首先这个数是一个质数,因为这个数没有被标记说明了这个数与之前的那个质数互质,由于这个数与质数互质,所以这个数当然就一定是质数了。而且这个数是往后第一个与当前质数互质的数,所以我们可以知道这个数是往后的第一个质数,因为之前的数都是当前质数的倍数。所以之前的数都是合数。所以这个数一定是当前质数往后遇到的第一个质数,也就是下一个质数了。
代码:

int prime[max_n];//第i个素数
bool is_prime[max_n+1]//is_prime[i]为ture表示i是素数
//返回n以内素数的个数
int sieve(int n){
    int p=0;
    for(int i=0;i<=n;i++) is_prime[i]=ture;
    is_prime[0]=is_prime[1]=false;
    for(int i=2;i<=n;i++){
        if(is_prime[i]){
          prime[p++]=i;
          for(int j=2*i;j<=n;j+=i) is_prime[j]=false;        
      }
   }
   return p;
}

基本实现:
首先,列出从2开始的所有自然数,构造一个序列:
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, …(加粗为删除的意思)
取序列的第一个数2,它一定是素数,然后用2把序列的2的倍数筛掉:
3,4, 5,6, 7,8, 9,10, 11,12, 13,14, 15,16, 17,18, 19,20, …
取新序列的第一个数3,它一定是素数,然后用3把序列的3的倍数筛掉:
5,6, 7,8,9,10, 11,12, 13,15,16, 17,18, 19,20, …
取新序列的第一个数5,然后用5把序列的5的倍数筛掉:
7,8,9,10, 11,12, 13,14,15,16, 17,18, 19,20, …
.不断筛下去,就可以得到所有的素数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值