poj-3292

来源:互联网 发布:手机淘宝兑换型优惠券 编辑:程序博客网 时间:2024/06/03 05:15
//5248K 16MS    G++#include <stdio.h>#include <string.h>const int MAX = 1000010;char HPNumber[MAX];int HSPNumber[MAX];void table() {    memset(HPNumber, 0 ,sizeof(HPNumber));    memset(HPNumber, 0 ,sizeof(HSPNumber));    // at begin, all H-number are h-prime    for (int i = 5; i <= MAX; i = i+4) {        for (int j = 5; j <= MAX; j = j+4) {            int multiply = i*j;            if (multiply > MAX) {                break;            }            // i and j are all h-prime, semi-h-prime            if (!HPNumber[i] && !HPNumber[j]) {                HPNumber[multiply] = -1;            } else { // i and j all not all semi-h-prime                HPNumber[multiply] = -2; // not semi-h-prime            }        }    }    int curHSPNum = 0;    for (int i = 1; i <= MAX; i ++) {        if (HPNumber[i] == -1) { // counter a h-semi-prime            curHSPNum++;        }        HSPNumber[i] = curHSPNum;    }}int N;int main() {    table();    while(scanf("%d", &N) != EOF) {        if (!N) {            return 0;        }        printf("%d %d\n", N, HSPNumber[N]);    }}

从解法上看算是个水题,就是纯遍历进行筛选,然后统计一下N之前有多少个H-semi-prime,

不过还是有重要思路的,首先,如何确定一个H-prime? 我最开始还向着是不是先搞一遍素数筛子,然后,再结合H-number来得到 H-prime,

后来,看了别人的题解,才发觉自己是想多了,完全可以假设一开始所有的h-number都是h-prime, 然后再从小到大的进行乘积筛选,逐渐去掉非h-prime,

同时根据乘积来判断 h-semi-number 和 非h-semi-number,

流程就是:

两重循环h-number,都是从5开始(最小的非1 h-number)这一点很关键,保证了算法的正确性,分别用i, j表示,

而 i * j 也必定是h-numner((4*A + 1)*(4*B + 1) 最后也可以表示为 4*C + 1 的形式), 如果 i 和 j 都是 h-prime, 那么 i*j 就是 h-semi-prime,在HP[]数组中将i 和 j置为 -1(初始为0,表示为h-prime)

而如果i 和 j 不全是h-prime, 那么i * j必定不是 h-semi-prime,因为必然可以表示为3个或以上的h-prime相乘, 置为-2(为何和 h-semi-prime 和 h-prime区分开)

最后遍历整个HP[]数组,统计一下每个数前面出现了多少个h-semi-prime即可。


这个题的思路本质上和素数筛子差不多,是不过多了一种标示罢了,都是先假设全部的数都是满足条件的,然后从小到大,一一排除.


0 0
原创粉丝点击