poj3292(筛法+打表)

Posted frankchen831x

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了poj3292(筛法+打表)相关的知识,希望对你有一定的参考价值。

题目链接:https://vjudge.net/problem/POJ-3292

题意:定义4n+1数(简称H数),H数分为三类:unit,即为1; H-primes,只能分解为1×自身,类似于我们平时说的素数; H-composites,除unit和H-primes数以外的H数。输入h,求[1,h]之间的H-composites数的个数。

思路:写了我3个多小时,因为题目理解错误和代码错误,写得崩溃。。QAQ。先说我想到的正确解法,注意到H-primes和我们说的素数基本类似,所以我们可以用欧筛法打表求出所有的H-primes,然后打表求出所有的H-composites,方法是枚举所有素数,如果这两个素数的乘积小于1e6+1,则记录为H-composites,要注意的是这里的判断不能写prime1[i]*prime[j]<=1000001,因为prime1[i]*prime[j]可能超出int范围,然后会导致段错误,所以应该除法判断(见代码)。然后对每一组输入h,二分查找<=h的最大H-composites数,它的下标+1即有多少个<=h的H-composites数,即所求结果。

AC代码:

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

const int maxn=1000005;
int h,vis[maxn],prime1[maxn],cnt1,prime2[maxn],cnt2;

void Prime(){
    memset(vis,1,sizeof(vis));
    for(int i=5;i<=1000001;i+=4){
        if(vis[i]) prime1[cnt1++]=i;
        for(int j=0;j<cnt1&&i*prime1[j]<=1000001;++j){
            vis[i*prime1[j]]=0;
            if(i%prime1[j]==0) break;
        }
    }
    memset(vis,0,sizeof(vis));
    for(int i=0;i<cnt1;++i){
        int tmp=1000001/prime1[i];
        for(int j=i;j<cnt1&&prime1[j]<=tmp;++j)
            vis[prime1[i]*prime1[j]]=1;
    }
    for(int i=5;i<=1000001;i+=4)
        if(vis[i])
            prime2[cnt2++]=i;
}

int bs(int x){
    if(x<25) return 0;
    int l=0,r=cnt2-1,m;
    while(l<=r){
        m=(l+r)>>1;
        if(x>=prime2[m]&&x<prime2[m+1]) break;
        if(x<prime2[m]) r=m-1;
        else l=m+1;
    }
    return m+1;
}

int main(){
    Prime();
    prime2[cnt2]=0x3f3f3f3f;    
    while(~scanf("%d",&h),h){
        printf("%d ",h);
        printf("%d
",bs(h));
    }
    return 0;
}

 

以上是关于poj3292(筛法+打表)的主要内容,如果未能解决你的问题,请参考以下文章

Semi-prime H-numbers POJ - 3292 打表(算复杂度)

poj 3292 Semi-prime H-numbers

浴谷夏令营2017.8.1数论的整理

POJ3292 Semi-prime H-numbers

POJ 2478 欧拉函数(欧拉筛法) HDU 1576 逆元求法

POJ 3292 Semi-prime H-numbers