本题大概可以算是线性筛算法的延伸。

如果之前还不屑知道线性筛,欢迎光临小蒟蒻的这篇关于线性筛模板和理解的博客。

题意:形如(4*k+1)的数被称为H数(k是非负数),如1,5,9……。除了自身和1以外没有一个H数因子的数被称为H素数,如125=5*5*5。只能分解成两个H素数之积的数被称为准H素数,如441=21*21。给出若干个数ai,求对于每个ai,1-ai中有多少个准H素数。

数据范围:1<=ai<=1e6+1。

 

我们知道,(4*a+1)*(4*b+1)=4*(4*a*b+b+a)+1。因此,两个H数相乘还是H数。那么,我们可以套用线性筛,O(n)求出H素数。如果能顺带求出准H素数,这道题就算解决了。我们知道,线性筛是对于每个H数x枚举H素数v,将x*v标记为非H素数。此时,我们只需判断x是否为H素数即可判断x*v是否是准H素数了。

 

一些细节处理详见代码:

 1 #include <cstdio>
 2 using namespace std;
 3 const int sz=1e6+5;
 4 int a[sz],mx,l,z[sz],len,h[sz],sum[sz];
 5 int main(){
 6     while(scanf("%d",&a[++l])){
 7         if(a[l]==0)break;
 8         if(a[l]>mx)mx=a[l];
 9     }
10     for(int i=1;i<=(mx-1)/4;i++){
11         sum[i]=sum[i-1];
12         if(h[i]==0)z[++len]=i;
13         else if(h[i]==2)sum[i]++;
14         for(int j=1;j<=len&&(z[j]*4+1)*(i*4+1)<=mx;j++){
15             h[4*z[j]*i+z[j]+i]=1;
16             if(h[i]==0)h[4*z[j]*i+z[j]+i]++;
17             if((i*4+1)%(z[j]*4+1)==0)break;
18         }
19     }
20     for(int i=1;i<l;i++)
21         printf("%d %d\n",a[i],sum[(a[i]-1)/4]);
22     return 0;
23 }