题意:对于4*n+1(n为自然数)组成的集合,乘法在该集合中是封闭的。现规定h-prime是这个集合的数字中只有1和本身能整除的数(不含1)。其余为h合数。从h合数中划分出一部分数字,这些数是由两个h素数相乘得到的,称之为h-semi。现要求在指定1~n范围内有多少个h-semi。
分析:筛法,就是把h合数全筛掉,开始默认所有的都是h素数,然后枚举两个数,把他们的乘积筛掉。这道题要求h-semi,所以我们要改进一下,把原来的true false标注变为0(h素数), 1(非h-semi的合数), 2(h-semi)的标注。在筛的过程中如果发现枚举的两个数暂时没被筛掉,我们就把他们的乘积标注为h-semi(前提是它没被标为1)。容易论证,任何一个非h-semi的合数在此过程中都会至少被标为1一次(设a<=b<=c,为三个组成非h-semi,d的因子。枚举到a,c时,a*c被标为2。然后会枚举到b和a×c。则必然将a*b*c标为1),所以即使我们之前误标为2,后来也会被更正为1。
View Code
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
usingnamespace std;
#define maxn 250005
int n, prime[maxn], ncount[maxn];
int main()
{
//freopen("D:\\t.txt", "r", stdin);
memset(prime, 0, sizeof(prime));
int temp;
n = maxn *4;
for (int i =1; (i *4+1) * (i *4+1) <= n; i++)
{
for (int j = i; (temp = (i *4+1) * (j *4+1)) <= n; j++)
{
if (prime[i] ==0&& prime[j] ==0&& prime[(temp -1) /4] !=1)
prime[((i *4+1) * (j *4+1) -1) /4] =2;
else
prime[((i *4+1) * (j *4+1) -1) /4] =1;
}
}
ncount[0] =0;
for (int i =1; i < maxn; i++)
if (prime[i] ==2)
ncount[i] = ncount[i -1] +1;
else
ncount[i] = ncount[i -1];
while (scanf("%d", &n) != EOF && n !=0)
{
printf("%d %d\n", n, ncount[(n -1) /4]);
}
return0;
}
#include <cstdlib>
#include <cstring>
#include <cstdio>
usingnamespace std;
#define maxn 250005
int n, prime[maxn], ncount[maxn];
int main()
{
//freopen("D:\\t.txt", "r", stdin);
memset(prime, 0, sizeof(prime));
int temp;
n = maxn *4;
for (int i =1; (i *4+1) * (i *4+1) <= n; i++)
{
for (int j = i; (temp = (i *4+1) * (j *4+1)) <= n; j++)
{
if (prime[i] ==0&& prime[j] ==0&& prime[(temp -1) /4] !=1)
prime[((i *4+1) * (j *4+1) -1) /4] =2;
else
prime[((i *4+1) * (j *4+1) -1) /4] =1;
}
}
ncount[0] =0;
for (int i =1; i < maxn; i++)
if (prime[i] ==2)
ncount[i] = ncount[i -1] +1;
else
ncount[i] = ncount[i -1];
while (scanf("%d", &n) != EOF && n !=0)
{
printf("%d %d\n", n, ncount[(n -1) /4]);
}
return0;
}