UVA 10533 - Digit Primes ( 素数筛, 埃式筛法 )

题意

求a~b内有多少个数满足本身是素数且各位相加后的结果也是素数

思路

1 不 是 素 数

因为这个debug了两个小时WA了四次也很可以
用普通素数筛就能做, 优化一下用Eratosthenes筛法也行
先说用普通素数筛:
只需要先筛选出1-54内的素数( 最大的各位相加是999999这个数 最大54 ) 然后对1~1000000所有数字求出各位相加的结果, 如果各位相加得到的是素数, 再判其本身是否是素数, 做前缀和就可以
用埃式筛法的话就直接判1~1000000内所有素数存一下, 做前缀和

AC代码

普通素数筛

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<cmath>
using namespace std;
const int maxn = 1000000+5;
set<int> pr;
int pre[maxn];

void primer()
{
    bool flag;
    for( int i = 2; i < 60; i++ )
    {
        flag = 1;
        for( int j = 2; j*j <= i; j++ )
        {
            if( i % j == 0 )
            {
                flag = 0;
                break;
            }
        }
        if(flag) pr.insert(i);
    }
}

bool isprimer(int num)
{
    if(num==1) return false;
    for( int i = 2; i*i <= num; i++ )
    {
        if( num % i == 0 )
            return false;
    }
    return true;
}

int main()
{
    primer();
    int dig, num;
    pre[0] = 0;
    for( int i = 1; i <= 1000000; i++ )
    {
        dig = i, num = 0;
        while(dig)
        {
            num += dig % 10;
            dig /= 10;
        }
        if( pr.count(num) )
        {
            if( isprimer(i) )
                pre[i] = pre[i-1] + 1;
            else
                pre[i] = pre[i-1];
        }
        else pre[i] = pre[i-1];
    }
    int n, a, b;
    scanf("%d",&n);
    while(n--)
    {
        scanf("%d%d",&a,&b);
        if( a > b ) swap(a, b);
        printf("%d\n", pre[b]-pre[a-1]);
    }
    return 0;
}

埃式筛法

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<cmath>
using namespace std;
const int maxn = 1000000+5;
bool ok[maxn];
int pre[maxn];

int main()
{
    int dig, num;
    ok[0] = 0, ok[1] = 1;
    for( int i = 2; i <= 1000000; i++ )
    {
        if( !ok[i] )
        {
            dig = i, num = 0;
            while(dig)
            {
                num += dig % 10;
                dig /= 10;
            }
            if( !ok[num] )
            {
                pre[i] = 1;
            }
            for(int j = 2*i; j <= 1000000; j += i)
                ok[j] = 1;
        }
    }
    for(int i = 1; i <= 1000000; i++)
        pre[i] += pre[i-1];
    int n, a, b;
    scanf("%d",&n);
    while(n--)
    {
        scanf("%d%d",&a,&b);
        if( a > b ) swap(a, b);
        printf("%d\n", pre[b]-pre[a-1]);
    }
    return 0;
}

转载于:https://www.cnblogs.com/JinxiSui/p/9740531.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值