Semi-prime H-numbers(POJ 3292)

POJ 3292 Semi-prime H-numbers

题目大意:

​ 形如 4 n + 1 4n + 1 4n+1的数被称为 H H H数,乘法在“ H − H- H数”内组成集合是封闭的,在这个集合中只能被 1 1 1和它本身整除的数叫“ H − H- H素数“,其余的数叫做” H − H- H合数“,在” H − H- H合数“中还存在着” H − H- H合成数“,” H − H- H合成数“是一个只能分解成两个“ H − H- H素数“乘积的” H − H- H合数“(可能有多种分解方案),例如, 441 = 21 ∗ 21 = 9 ∗ 49 441 = 21 * 21 = 9 * 49 441=2121=949,所以 441 441 441是” H − H- H合成数“

0 ∼ h 0 \sim h 0h范围内的” H − H- H合成数“的个数。

输入

若干行,每一行一个小于等于 1000001 1000001 1000001的整数 k k k,一个 0 0 0表示输入结束

输出

对于每一行输入,先输出这个数然后空格,再输出这个数对应的答案

样例输入
21 
85
789
0
样例输出
21 0
85 5
789 62

思路很简单,首先将所有范围内的 H H H数中的 H H H素数全部找出来,因为 H H H数满足 4 n + 1 4n + 1 4n+1,因此可以从 5 5 5开始,每次加 4 4 4,然后找 H H H素数,可以通过埃氏筛法的思路来求,对于第一个出现的 H H H数,一定是 H H H素数,因此这个数的所有倍数一定不是 H H H素数,做好相应标记,同时打表记录下来。

找到所有的 H H H素数之后,就可以双重循环把所有的可能的情况乘一下,乘出来的结果,如果是 H H H数,那么一定是 H H H合成数。最后再范围内找个数,通过一个前缀和即可

代码

#include <iostream>
#define N 1000005
#define ll long long
using namespace std;
int semi_prime[N];
int h[N], h_prime[N];
int cnt;

void solve() {
	for(int i = 5; i < N; i += 4) {
		if(h[i]) continue;
		h_prime[++cnt] = i; //存所有的H素数
		for(int j = i * 2; j < N; j += i) //将i这个H素数的所有倍数筛掉
			h[j] = 1;
	}
	for(int i = 1; i <= cnt; i++) {
		if(h_prime[i] * h_prime[i] > N) break; //剪枝,避免超时
		for(int j = i; j <= cnt; j++) {
			ll k = h_prime[i] * h_prime[j]; //剪枝
			if(k > N) break;
			if(k % 4 == 1) //如果两个H素数之积是H数,那么一定是H合成数,记录相应位置
				semi_prime[k] = 1;
		}
	}
	for(int i = 1; i < N-1; i++) //前缀和
		semi_prime[i] += semi_prime[i-1];
}
int main () {
	ios::sync_with_stdio(0);
	int h;
	solve();
	cin >> h;
	while(h) {
		cout << h << " " << semi_prime[h] << "\n";
		cin >> h;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值