今天下午数据结构大作业pre相当成功啊
题意
定义H number为形如4*i+1的正整数,i为任意非负整数,注意H数乘法封闭。
定义H prime number 为除了1和它本身,无法被其他H数整除的数字,1不是prime number。
定义H-semi-prime number为由两个H prime number相乘得到的H数。
给出一个数字,问小于等于这个数字的H-semi-prime number有多少个。
输入输出
Input
Each line of input contains an H-number ≤ 1,000,001. The last line of input contains 0 and this line should not be processed.
Output
For each inputted H-number h, print a line stating h and the number of H-semi-primes between 1 and h inclusive, separated by one space in the format shown in the sample.
分析
由于一开始对筛法的理解不够,加上一开始代码写挫了,我一直觉得不能跑两遍筛法(第二遍为类筛法),但其实是可以的。
实际上,筛法的时间开销小,不主要是因为它删除了很多点,而是因为第二重循环它是跳着跑的。
我的解法是先跑一边筛法,筛素数,然后二重循环遍历所有的素数,将其乘积设为semi-prime,只要加上两数相乘小于最大值的判断,就可以了,事实上第二遍素数的计算次数应当比第一次筛法小。一开始没加两数相乘小于最大值,结果跑半天才跑出来。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define mxn 1000010
int n,cnt;
int semi[mxn];
int is_hp[mxn];
int p[mxn];
void set(){
cnt=0;
memset(is_hp,0,sizeof(is_hp));
for(int i=1;4*i+1<mxn;++i) if(is_hp[4*i+1]==0)
for(int j=i;(long long)(4*i+1)*(4*j+1)<mxn;++j){
int tem=(4*i+1)*(4*j+1);
is_hp[tem]=1;
}
int cur=0;
for(int i=1;4*i+1<mxn;++i) if(is_hp[4*i+1]==0)
p[cur++]=4*i+1;
for(int i=0;i<cur;++i)
for(int j=i;j<cur&&(long long)p[i]*p[j]<mxn;++j)
semi[cnt++]=p[i]*p[j];
sort(semi,semi+cnt);
cnt=unique(semi,semi+cnt)-semi;
}
int bin(int l,int r){
int m;
while(l+1<r){
m=(l+r)>>1;
if(semi[m]<=n) l=m;
else r=m;
}
if(semi[l]<=n) return l+1;
return 0;
}
int main(){
set();
while(scanf("%d",&n)!=EOF){
if(!n) break;
int ans=bin(0,cnt);
printf("%d %d\n",n,ans);
}
return 0;
}