HDU-#1239、2136、2138 HDU素数筛法系列

        素数筛法是code中很重要的一个点,经常用于各种小技巧和细节处,这里将素数筛法知识点总结下以及对HDU上的三道初级题目进行题解说明。

       【知识点补充:素数筛法】:

         今天突然看见这篇之前写的博客,是一篇关于素数筛法的博客,因此在这里总结下,算是复习吧!

        筛法的方法很简单:在一个范围为n的区间,对与不超过n的每个非负数num,删除2num、3num、4num、5num...倍数的数,遍历完整个区间,那么剩下的数就是素数。很常见也是下面code用到的一种方法是利用一个vis[]数组来进行标记,不是素数标记为1,是则初始化为0,这样整个区间为0的下标i即为素数。核心code:

memset(vis,0,sizeof(vis));
for(int i=2; i<=n; i++) //判断n以内的质数
    for(int j=2; j*i<=n; j++)
         vis[i*j]=1;
        但这样的筛法是有局限性的,尽管还可以进一步进行优化。但意义不大,这段code已经非常高效了。 适用于10^6范围内的素数筛选。那么可以怎样改进?让它再快一点呢。可以缩小判断范围,一是我们不用遍历到n,而只需要到sqrt(n)即可,然后对num的判断也只需要限定其为素数即可。最后在第二层循环的遍历,起点可以从i^2开始,因为i*2,在i=2时已经判断了。综上改进的code如下:

memset(vis,0,sizeof(vis));
for(int i=2;i<=sqrt(n+0.5);i++)
    if(!vis[i]){
        prime[k++]=i; //记录素数
        for(int j=i*i;j<=n;j+=i)
            vis[j]=1;
    }

       当然方法还有很多,感兴趣可以多多探究下......

        【题解如下:1239、2136、2138】

         #1239:Calling Extraterrestrial Intelligence Again

        题目大意:给定m,a,b,要求在范围内求两个质数p,q,满足p/q>=a/b,p*q<=m,并且质数的乘积尽量大。

        解题思路:先可以根据数据范围将素数表进打表处理,在输入数据后直接进行判断。判断的时候注意判断范围,防止TLE,详见code。

        题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=1239

        code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;

const int MAXN = 10001;
int prime[MAXN];
bool isp[MAXN];
int m,a,b,p,q,num=0;

void init_prime(){
    memset(prime,0,sizeof(prime));
    memset(isp,0,sizeof(isp));
    double d=sqrt(10000*1.0);
    for(int i=2; i<=d; i++) //判断10000以内的质数
        for(int j=2; j*i<10000; j++)
            isp[i*j]=1;
    for(int i=2;i<MAXN;i++){ //记录质数以及计数
        if(!isp[i]){
            prime[num]=i;
            num++;
        }
    }
}

int main(){
    init_prime(); //计时之前进行打表初始化
    while(scanf("%d%d%d",&m,&a,&b)!=EOF && (m || a || b)){
        float c=a*1.0/b;
        int d,pro,max=0;
        for(int i=num-1;i>=0;i--){ //注意循环范围
            for(int j=num-1;j>=i;j--){
                pro=prime[i]*prime[j];
                d=prime[i]*1.0/prime[j];
                if(pro<=m && d>=c){ //条件判断
                    if(pro>max){ //判断是否为最大积
                        max=pro;
                        p=prime[i];
                        q=prime[j];
                    }
                    else break;
                }
            }
        }
        printf("%d %d\n",p,q);
    }
    return 0;
}

      #2136:Largest prime factor

     题目大意:给所有质数编号,其余的数编号为最大质数的序号。任意输入一个数,询问其编号是多少?

     解题思路:类似素数打表,将素数以及素数的倍数进行同样的编号。那么素数编号是递增的,而其它数均会被最大素数的编号覆盖。

     题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=2138

     code:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

const int MAXN = 1e6;
int pri[MAXN],n,k;

void init_prime(){
    k=0;
    memset(pri,0,sizeof(pri));
    for(int i=2;i<=MAXN;i++){
        if(!pri[i]){
            k++; //编号
            for(int j=i;j<=MAXN;j+=i) //对所有质数以及质数的倍数进行编号
                pri[j]=k;
        }
    }
}

int main(){
    init_prime();
    while(scanf("%d",&n)!=EOF)
        printf("%d\n",pri[n]);
    return 0;
}

      #2138:How many prime numbers

     题目大意:给出数据,判断该组数据中有多少个素数?

     解题思路:开始以为测试数据量会很大,担心会T,直接打表了,结果超内存了。然后改了下,小数据打表,大数据暴力判断,结果还是不行。最后直接对输入的数据进行输入一个判断一下,然后计数,一下就A了。想了下,时间复杂度为O(N),是可行的!很伤心,其它的很简单,详见code。

     题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=2136

     code:

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;

int n,num,ans;

int isprime(int m){ //直接判断
    int sq=(int)sqrt(m+0.5);
    for(int i=2;i<=sq;i++)
        if(m%i==0) return 0;
    return 1;
}

int main(){
    while(scanf("%d",&n)!=EOF){
        ans=0;
        for(int i=0;i<n;i++){
            scanf("%d",&num);
            if(isprime(num) && num!=1) ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值