XTU-OJ 《C语言程序设计》 1098-素数个数

Description

给定两个非负整数a,b,其中0<= a,b<=1,000,000,请计算这两个数之间有多少个素数。

输入

第一行是一个整数K(1<=K<=1000),表示有多少个样例,每个样例占一行,是两个整数a和b,每个整数之间用一个空格隔开。

输出

每行输出一个样例的结果。

Sample Input

2
2 3
17 19

Sample Output

2
2

解题思路:

像这类 “求一个区间中有多少个符合条件的数” 的问题,一般考虑用 前缀和 的方法求解。

何为前缀和,举个不恰当的例子:字符串 abcdefghigklmn,a的前缀和是 a,b的前缀和是 a+b,……, f 的前缀和是 a+b+c+d+e+f。 

放在数组中,前缀和就是  Sa[i] = a[0]+a[1]+a[2]+ ······ +a[i]。

所以这个题转化成前缀和的方法:0~b之间素数的个数 减去  0~a-1之间素数的个数,就是所求a,b之间素数的个数。

现在的问题就是判断 每个数是否为 素数,这里有个非常强大的筛选素数方法——欧拉筛(线性筛),所有数字只要遍历一遍就能判断出其是否为素数。

代码中 isPrime() 函数 就是 欧拉筛 的代码实现。(除了第15行,这行是结合题目加的)

利用欧拉筛,我们得到了一个books[]数组,books[i] = 1表示 i 为 素数, books[i] = 0 为非素数。现在对 books数组进行前缀和累加,得到 表示数字i之前有多少个素数的 books数组。(36、37行)

现在所有的问题迎刃而解,不管你怎么问,怎么变化a,b的值,我都能够一秒给出答案:books[b] - books[a-1]。

AC代码:

#include <stdio.h>

const int MAXN = 1e6;
bool vis[MAXN+2];
int prime[80000];
int books[MAXN+2];

void isPrime()                      //欧拉筛(线性筛) 
{
    for (int i = 2; i < MAXN; i ++)
    {
        if ( !vis[i])
        {
            prime[++prime[0]] = i;
            books[i] = 1;          //  数字i为素数记为1,非素数默认为0
        }
        for (int j = 1; j <= prime[0] && i <= MAXN/prime[j]; j ++)
        {
            vis[i*prime[j]] = 1;
            if (i % prime[j] == 0)
                break;
        }
    }
}

void swap(int &x, int &y)
{
    int t = x;
    x = y;
    y = t;
}

int main()
{
    isPrime();
    for (int i = 1; i <= MAXN; i ++)     // 0到数字i间一共有多少个 素数
        books[i] += books[i-1]; 
    int k,a,b;
    scanf("%d",&k);
    while (k --)
    {
        scanf("%d %d",&a,&b);
        if (a > b)  swap(a,b);         //  注意题目没限定a b 的大小关系
        printf("%d\n",books[b]-books[a-1]);
    }
    return 0;
}

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值