题意:定义一种新的数叫H数,它们是所有形如4k+1的整数,其中,k是非负整数。在这个题目中,只考虑H数而不考虑其他整数。同时定义了H质数和H合数,H质数即只能被1和本身整除(注意,这个时候的“只能”只局限在H数范围内),H合数即恰好可以分解为两个H质数的乘积。
现在给出一个H数h,问1到h中,有多少个H合数。
这个纯粹是把通常意义的整数的整除和质数、质因子的概念做了一个整体改变,放在4k+1型数下考虑,题目读明白了就可做了。
思路:首先预处理出所有的H数,找出1000000以内的就够了,不难想到实际规模是250000,在这个过程中同时判定每个H数是不是H质数,这个是因为我得到一个H数时,我肯定已经得到了比它小的H数,因此,一定可以判断现在这个H数是不是H质数。用一个m数组来标记,如果H数i为H质数,就标记m[i]=1,否则为0.
其次就是做第二张表了,这张表用一个一维数组table来实现,其中table[i] 是第i个H数及其之前有多少个H合数,具体步骤是:对每个H数,如果它是H质数,那么在它及以前的H合数的数目一定等于上一个H数及其之前的H合数数目,因为本身是质数嘛,不增加答案,即table[i]=table[i-1] ,如果不是H质数的话就对其进行分解,看能否找到一个H质数(注意必须是H质数而不仅仅是H数)来整除它,且商依然是H质数(这样的话就代表这个数可以分解为两个H质数的乘积了),这样就得到了一个H合数,答案加一,并计入table[i]
当然还有种可能,这个H数并不是H质数,然而它却也不是H合数,这时要在后面再加一个判断(即代码中的check变量),这种情况出现了的话,就继承上一个H数的答案,即table[i]=table[i-1]
这就得到了答案表了,直接打表即可
code:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<algorithm>
#include<cstdlib>
#define maxn 1001010
#define inf 0x3f3f3f3f
#define LL long long
using namespace std;
int m[1000100];
int table[250050]= {0};
void init()
{
memset(m,0,sizeof(m));
m[1]=m[5]=1;
for(int i=2; 4*i+1<=1000005; i++)
{
int tmp=4*i+1;
bool check=true;
for(int j=1; j<i&&((4*j+1)*(4*j+1))<=tmp; j++)
{
int tp=4*j+1;
if(tmp%tp==0)
{
int tpp=tmp/tp;
if((tpp-1)%4==0)
{
check=false;
}
}
}
if(check)m[tmp]=1;
}
return;
}
void init2()
{
int n=1000001;
int ans=0;
int r=(n-1)/4;
for(int i=1; i<=r; i++)
{
int tmp=4*i+1;
bool check=true;
if(m[tmp])
{
table[i]=table[i-1];
continue;
}
for(int j=1; j<i; j++)
{
int tp=4*j+1;
if(tp*tp>tmp)break;
if(m[tp])//找到一个H质数
{
if(tmp%tp==0)//如果这个H质数能整除tmp
{
if(m[tmp/tp])//且商还是个H质数,就得到H合数了
{
check=false;
ans++;
table[i]=ans;
break;
}
}
}
}
if(check)table[i]=table[i-1];//不是H质数却也不是H合数的情况,继承答案
}
}
int main()
{
int n;
init();
init2();
while(scanf("%d",&n)&&n)
{
printf("%d %d\n",n,table[(n-1)/4]);
}
}