Semi-prime H-numbers
题目大意
将形如4n+1的数定义为H-Number,其对于乘法的封闭性显然。将可以分解为两个及以上H-Number之积的H-Number定义为H-Composites,否则为H-Prime。H-Composites有一个子集H-Semiprime,指最多只能分解成两个H-Number之积的H-Composites。现在对于每次询问h,希望你能求出小于h的H-Semiprime的个数。
h <= 1e6 + 1
解法
考虑H-Prime和普通质数的相似性,我们可以联想到类似欧拉筛的筛法。将欧拉筛的循环稍作改动之后,我们得到了一个H-Prime筛:
1 | const int N = 1e6 + 5; |
进一步我们发现,在筛选的过程中,每次给 i * pri[j]
打H-Compiosites标记的时候,首先 pri[j]
必定是H-Prime,只需要判断 i
是否是H-Prime即可确定 i * pri[j]
是否是H-Semiprime,所以我们可以一边筛一遍标记H-Semiprime。于是代码就变成了这样:
1 | const int N = 1e6 + 5; |
想强调的一点是,因为我太菜了,所以我一开始把 semi[i * pri[j]] = 1;
写成了 semi[i * pri[j]]++;
。我一开始觉得这两种写法从结果上来说并没有什么区别,但事实上对于比如693这样的数,会因为9 * 77和21 * 33被重复标记。
最后只需要求一下semi数组的前缀和然后O(1)回答每个询问就可以了。完整代码如下:
1 |
|