a-贝利福斯数 (各种线性筛)

链接:https://www.nowcoder.com/acm/contest/158/D
来源:牛客网
 

题目描述

将所有形如ax+1的数称为a-贝利福斯数,其中x是正整数。
一个a-贝利福斯数是a-贝利福斯素数,当且仅当它不能被分解成两个a-贝利福斯数的积。
现在给出a,n,问有多少个 ≤ n的a-贝利福斯数可以被分解成两个a-贝利福斯素数的积。

输入描述:

一行两个数a,n

输出描述:

一行一个数表示答案

示例1

输入

复制

4 25

输出

复制

1

先看一下欧拉筛素数的方法

const int N=1e5+10;//!!!修改 N 
int prime[N];
bitset<N> vis; 
void get_pri(){
    int cnt = 0;  
    for(int i = 2; i <= N; i++){
        if(!vis[i])prime[cnt++] = i;     
        for(int j = 0; j<cnt && 1LL*i*prime[j]<=1LL*N; j++){
            vis[i*prime[j]]=1;//找到的素数的倍数不访问 
            if(i % prime[j] == 0) break;//关键!!!! 
        }
    }
}

这道题,相同的思想,最后枚举两个素数看看他们的乘积是否出现过就好了

#include<bits/stdc++.h>
using namespace std;


typedef long long ll;
#define rep(i,a,b) for(int i=a;i<b;i++)
#define per(i,a,b) for(int i=b-1;i>=a;i--)
const int maxn=2e7+10;


bitset<maxn*10> vis;
int cnt_pri,pri[maxn/2];
int num[maxn];

void init(int a,int n){
    cnt_pri=0;int cnt_num=0;
    for(int i=a+1;i<=n;i+=a)num[cnt_num++]=i;

    for(int i=0;i<cnt_num;i++){
        if(!vis[num[i]])pri[cnt_pri++]=num[i];
        for(int j=0;j<cnt_pri&&1LL*pri[j]*num[i]<=n;j++){
            vis[1LL*pri[j]*num[i]]=1;
            if(num[i]%pri[j]==0)break;
        }
    }
}

int main(){
    //freopen("123.txt","w",stdout);
    //double t1=clock();
    int a,n;
    scanf("%d %d",&a,&n);
    init(a,n);
    //printf("%.2f\n",(clock()-t1)/CLOCKS_PER_SEC);
    ll ans=0;
    for(int i=0;i<cnt_pri;i++){
        if(1LL*pri[i]*pri[i]>n)break;
        for(int j=i;j<cnt_pri;j++){
            ll sum=1LL*pri[i]*pri[j];
            //printf("sum:%lld\n",sum);
            if(sum>n)break;
            if(vis[sum])ans++;//答案肯定是合数,我们肯定已经筛掉了,这样可以节省空间 
            vis[sum]=0;
        }
    }
    printf("%lld\n",ans);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值