poj3292

题意:对于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 >
using namespace 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 ]);
}
return 0 ;
}

你可能感兴趣的:(poj)