hackerrank w29 Megaprime Numbers

Problem

找出区间[l,r]之间由{2,3,5,7}四种数字组成的质数的个数
1lr1015
0rl109

Solution

设由{2,3,5,7}四种数字组成的数为A类数,A类数中的质数为B类数,我们要求的是B类数的个数。
由于有条件0rl109,那么区间[l,r]内A类数最多有49=262144个,那么最开始我们需要找到第一个大于等于l的A类数,接着我们可以仿照四进制加法来找到下一个这样的A类数,判断一个A类数是不是质数就可以直接用Miller_Rabin。

Code

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<set>
#include<map>

#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)

using namespace std;

typedef long long LL;
typedef double db;

struct number{int len,a[20];}L,R;
bool bz[10];
int nxt[10]={2,2,3,5,5,7,7,2,0,0};
int pri[11]={0,2,3,5,7,11,13,17,19,23,29};
bool operator < (number a,number b){
    if (a.len!=b.len)return a.len<b.len;
    fd(i,a.len,1)
    if (a.a[i]!=b.a[i])return a.a[i]<b.a[i];
    return 1;
}

void getnum(LL x,number &a){
    a.len=0;
    while(x){
        a.a[++a.len]=x%10;
        x/=10;
    }
}

void init(number &a){
    int w=0;
    fd(i,a.len,1)
    if (!bz[a.a[i]]){w=i;break;}
    if (w){
        if (a.a[w]>7){
            fo(i,1,w)a.a[i]=0;
            a.a[w+1]++;
            if (w==a.len)a.a[++a.len]=1;
            init(a);
            return;
        }
        a.a[w]=nxt[a.a[w]];
        fo(i,1,w-1)a.a[i]=2;
    }
}

number getnxt(number a){
    int w=a.len+1;
    fo(i,1,a.len)
    if (a.a[i]!=7){w=i;break;}
    a.len=max(a.len,w);
    fo(i,1,w)a.a[i]=nxt[a.a[i]];
    return a;
}

LL quickmi(LL x,LL tim,LL mo){
    LL ans=1;
    while(tim){
        if (tim%2)ans=ans*x%mo;
        x=x*x%mo;
        tim/=2;
    }
    return ans;
}

bool check(LL x,LL p,LL t,LL mo){
    x=quickmi(x,p,mo);
    if (x==mo-1||x==1)return 1;
    fo(i,1,t){
        if (x==1)return 0; 
        x=x*x%mo;
        if (x==mo-1)return 1;
    }
    return 0;
}

bool miller_rabin(number a){
    LL x=0;
    fd(i,a.len,1)x=x*10+a.a[i];
    LL p=x-1;
    int t=0;
    while(p%2==0){p/=2;t++;}
    fo(i,1,10){
        if (x==pri[i])return 1;
        if (!check(pri[i],p,t,x))return 0;
    }
    return 1;
}

int main(){
    LL l,r;
    scanf("%lld%lld",&l,&r);
    getnum(l,L);
    getnum(r,R);
    bz[2]=bz[3]=bz[5]=bz[7]=1;
    init(L);
    int ans=0;
    while(L<R){
        if (miller_rabin(L)){
            ans++;
            fd(i,L.len,1)printf("%d",L.a[i]);putchar('\n');
        }
        L=getnxt(L);
    }
    printf("%d\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值