洛谷P1865 A%B Problem

传送门P1865https://www.luogu.com.cn/problem/P1865

Atcoder大多了的我一看到这个题目就以为是道省选难度的题,点进去一看:

直接给我吓傻,整不会了。

不开玩笑了,直接入题

这是一道素数筛+前缀和的题

第一步:思考

简单地思考一下后,你会惊奇发现:

设区间 [1,i] 的素数个数为 pre[i],则区间[l,r]的素数个数为pre[r] - pre[l - 1],

做到这里,题目已经解决了一半了

第二步:将问题逐个击破

第一个问题:咋么求sum[i]呢?

这和前缀和有点像,

         就是当i为素数时,pre[i] = pre[i - 1] + 1;

        否则,pre[i] = pre[i - 1]

就是这样:

for(int i = 1 ; i <= n ; i ++){
    if (prime[i]) pre[i] = pre[i - 1] + 1; // prime[i]表示如果i是否为素数,是为true,否则为false
    else pre[i] = pre[i - 1];
        // cout <<  i << " " << pre[i] << endl; 
}

第二个问题:那咋么求素数呢?

我们知道,有普通的方法,\sqrt{n}的,但是会超时,因为你每次都要验证一次,就是n \sqrt{n}

我这里的n是题目中的m,最大值为1e6。

所以我们要用更快捷,效率更高的方式,就是欧拉筛。

模版:

    for(int i = 2; i <= n; i++) prime[i] = true;
    for(int i = 2 ; i <= n ; i++){
        if (prime[i]){ lst[ ++ lst[0]] = i;}
        for(int j = 1 ; j <= lst[0] ; j ++) {
            if (i * lst[j] > n) break;
            prime[i * lst[j]] = false ;
            if (i % lst[j] == 0) break;
        }
    }

所以,总代码为:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define MAXN 1048586
#define M 5005
#define N 500005
#define lowbit(x) ((x)&(-(x)))
#define mod 998244353
#define all(s) s.begin(),s.end()
#define Mn(a,b,c) min(a,min(b,c))
#define Mx(a,b,c) max(a,max(b,c))
#define sq(x) ((x) * (x))
#define cub(x) ((x) * (x) * (x))
#define all(s) s.begin(),s.end()
#define e9 1000000000
#define int long long
#define endl "\n"
int yes(int dx){cout << "Yes" << endl;return 0;}
int no(int dx){cout << "No" << endl;return 0;}
string s;
bool prime[MAXN];
int lst[MAXN] ,pre[MAXN];
signed main(){
    int n,m,k;
    // init();
    cin >> m >> n;
    for(int i = 2; i <= n; i++) prime[i] = true;
    for(int i = 2 ; i <= n ; i++){
        if (prime[i]){ lst[ ++ lst[0]] = i;}
        for(int j = 1 ; j <= lst[0] ; j ++) {
            if (i * lst[j] > n) break;
            prime[i * lst[j]] = false ;
            if (i % lst[j] == 0) break;
        }
    }
    // 素数筛
    for(int i = 1 ; i <= n ; i ++){
        if (prime[i]) pre[i] = pre[i - 1] + 1;
        else pre[i] = pre[i - 1];
        // cout <<  i << " " << pre[i] << endl; 
    }
    //前缀和
    for(int i = 1 ; i <= m ;i ++) {
        int l , r;
        cin >> l >> r;
        if (l < 1 || r > n) cout << "Crossing the line" << endl;
        else cout << pre[r] - pre[l - 1] << endl;
    }
    return 0;
}

所有的问题都解决了,我的任务也完成了

完结撒花

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值