问题 D: 【数论】Semi-prime H-numbers

译文描述
这个问题是基于戴维·希尔伯特(David Hilbert)的一项练习得出的,戴维·希尔伯特(David Hilbert)在教学法上建议对4n + 1数的理论进行研究。在这里,我们只做一点。

H数是一个正数,是四的整数倍:1、5、9、13、17、21,…是H数。对于这个问题,我们假装这些是唯一的数字。H数在乘法下是闭合的。

与常规整数一样,我们将H数划分为单位,H素数和H组合。1是唯一的单位。如果H数h不是单位,则为H素数,并且仅以一种方式为两个H数的乘积:1×h。其余数字是H组合的。

例如,前几个H复合材料为:5×5 = 25、5×9 = 45、5×13 = 65、9×9 = 81、5×17 = 85。

您的任务是计算H半素数。H半素数是一个H数,正好是两个H素数的乘积。两个H-素数可以相等或不同。在上面的示例中,所有五个数字均为H-半质数。125 = 5×5×5不是H-半素数,因为它是三个H-素数的乘积。

输入
输入的每一行包含一个H数≤1,000,001。输入的最后一行包含0,并且不应处理此行。

输出
对于每个输入的H数h,以示例中显示的格式打印一行h,并在1和h之间(含1和h)打印H半素数。

这个题目就相当于让先筛选H-素数, 找0到h中有多少个数是两个h-素数乘到一起的,然后这个时候我们就改进一下筛选素数的方法, 如果i是一个H-素数,那么和i属于同一类的一定是i * (4x + 1) , 也就是将i乘上(4x + 1) , 题目规定(4x + 1)是h数, 所以i * (4x + 1)一定是H数 但一定不是H-素数,以为现在他有两个因子i和4i + 1 , 我们就这样构造一下,将线性筛选素数改改,然后就出来了,

#include <iostream>
using namespace std;
const int N = 1e6 + 10 ;
int vis[N] , prime[N] ; 
int cnt[N] ;
int st[N] ;
int tot ;
void get()
{
	for(int i = 5 ;i < N ;i += 4) 
	 {
	 	if(!vis[i]) 
	 	prime[++ tot] = i ;
	 	for(int j = i ;j < N ;j += 4 * i)
	 	 vis[j] = true ;
	 }
	 for(int i = 1 ;i <= tot ;i ++)
	  for(int j =  1 ;j <= i && prime[i] * prime[j] < N ;j ++)
	   st[prime[i] * prime[j]] = 1 ;
	for(int i = 1 ;i < N ;i ++)
	 cnt[i] = cnt[i - 1] + st[i] ; 
}
int main()
{
	get() ;
	int a , b ;
	while(cin >> a && a != 0)
	 cout << a << " " << cnt[a] << endl ;
	return 0;
}
posted @ 2019-10-08 18:46  spnooyseed  阅读(135)  评论(0编辑  收藏  举报