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 打表(算复杂度)