POJ3292 Semi-prime H-numbers

题目大意: H-numbers是4*n+1的数,H-primes是1*H-numbers,H-semi-primes是仅仅2个H-primes的数的乘积,然后问1~h(h是 H-numbers)里面有几个H-semi-primes。

思路:题目说的通俗的就是:给出一堆H数,然后HP数的就像素数的定义(姑且称为H素数),然后HSP数就是2个HP数的乘积,也就是找出2个H素数,他们的乘积就是我们要的结果。所以要把合数素数筛选出来。

在这多谢ZZY的提醒,如果要打表的话记得最好离线,其次是在线全部全部打表(不要留有一部分在里面),因为计时是多组数据一起计时的额。

做了这道题,深深感激筛选法的强大,也感觉对筛选法还没有较好的理解啊,下面举一个筛选例子:

比如按下面程序的进行的话:5*81的时候是第一次是成立的,但是在之后9*9后,81变成了合数,那么轮到81*5的时候5*81又变回不成立的了。

所以只要拿2个当前未标记为1的去筛选,那么最后肯定能筛选出来。

5 9 13 17 21 25 29 33 37 41 45 49 53 57 61 65 69 73 77 81 85 89 93 97 101 105 10

9 113 117 121 125 129 133 137 141 145 149 153 157

 

 

program:

#include<iostream>
using namespace std;
int flag[1000005];
int num[1000005];
int main()
{
 memset(flag,0,sizeof(flag));
 //memset(num,0,sizeof(num));
 for(__int64 i=5;i<=1000001;i+=4) //利用双重循环筛选,利用了素数筛选原理,前面的把后面的筛出来
    for(__int64 k=5;k<=1000001;k+=4)
       {
          if(i*k>1000001)break;   //卡主条件防爆
          else if(flag[i]==0 && flag[k]==0)
                     flag[i*k]=1;
          else flag[i*k]=-1;
       }
 int cnttt=0;      
 for(int i=1;i<=1000001;i++)
 {
   if(flag[i]==1)      //打表好用法啊,应区间打表而生,在前者的基础上再加。
     cnttt++;
   num[i]=cnttt;
             
 } 

int n;
while(scanf("%d",&n)!=EOF&&n) 
{
//memset(num,0,n*sizeof(num[0]));即使多了一句memset都超时啊
/*int cnttt=0;                             
for(int i=1;i<=n;i++)
 {
   if(flag[i]==1)
     cnttt++;
   num[i]=cnttt;
             
 }*/   
printf("%d %d\n",n,num[n]);
}
//system("pause");
return 0;}

 

你可能感兴趣的:(POJ3292 Semi-prime H-numbers)