zoukankan      html  css  js  c++  java
  • POJ 3292 Semi-prime H-numbers (素数筛法变形)

      题意:题目比较容易混淆,要搞清楚一点,这里面所有的定义都是在4×k+1(k>=0)这个封闭的集合而言的,不要跟我们常用的自然数集混淆。

      题目要求我们计算 H-semi-primes, H-semi-primes是 两个H-primes的乘积, H-primes的定义为:在这个集合中只能由1和它本来相乘得来,并且1不是 H-primes;

      分析:这个题目我一开始是想打表记录一下的,但是没有筛法的效率,数据量过大,程序崩溃了(连超时的机会都不给我),看了多个别人的做法才知道,这个题目考查的是对于素数筛法,我们需要对素数筛法有一些变形。和正常筛法是不太一样的,这个有三种数,H-semi-primes,H-primes, H-composite,这三种数我们需要给他们标上不同的号,而且必须是不同的号,否则筛法会出错误,最后题目问的是(1,h)之间有多少个,我们应该使用一个数组记录这个答案,以便打表以后在o(1)的复杂度就找到答案。

      注意:可能有人感觉会有漏解,其实不会,有人可能会担心这一点,类似这样,5×25怎么办? 但是25的标记一定不是0,25在5×5的时候就被标记了1,我们在后面能遇到的能被两个数乘积表达的数,在以前的时候就肯定已经被表达出来,并且标记过了。

      感悟:感觉素数筛法好神奇,它的变形好巧妙,好精美。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define maxn 1000001
    int prime[maxn+10];
    int ans[maxn+10];
    void make(){
        memset(prime,0,sizeof(prime));
        ///H—prime 标记为 0
        for(int i = 5;i <= maxn;i += 4){
            for(int j = 5;j <= maxn;j += 4){
                if(i*j > maxn) break;
                if(prime[i]==0 && prime[j]==0)///这个判断0的充要条件就是题目中给的要求,只能是两个H-prime
                    ///任意一个为1或者2都不可以
                    prime[i*j] = 1;///H-semi-primes标记为1;
                else prime[i*j] = 2;/// H-composites必须为2或者其他
            }
        }
    }
    void get_ans(){
        int tot = 0;
        for(int i = 1;i <= maxn;i++){
            if(prime[i] == 1) tot++;///don't forget prime[i] shoule only be 1;
            ans[i] = tot;
        }
    }
    int main(){
        int h;
        make();
        get_ans();
        while(~scanf("%d",&h)){
            if(!h) break;
            printf("%d %d
    ",h,ans[h]);
        }
        return 0;
    }
  • 相关阅读:
    sc delete 服务器名提示“指定的服务已经标记为删除”
    visio2007无法拖动
    Oracle 时间相减得出毫秒、秒、分、时、天,,【转】
    服务启动错误1053解决方案之一
    【转】oracle 删除重复记录
    利用VS2013 XSLT对 XML进行转换
    xpath属性值的模糊匹配
    android 与 小米1S刷机学习
    如何添加打印机
    SVN学习(一)——SVN 检出文件步骤、图标显示及含义
  • 原文地址:https://www.cnblogs.com/jifahu/p/5580298.html
Copyright © 2011-2022 走看看