B4356 [GESP202506 二级] 幂和数
欢迎报名洛谷网校,报名课程可以获得对应组别的知识点讲解与答疑服务,期待和大家一起进步!点击图片即可报名。
:::align{center} :::
本题介绍三种做法,每一种做法都可以通过本题。第二种做法和第三种做法都有优秀之处。
最直接的做法(足以通过本题)
知识点:循环嵌套、数学库 pow 函数。
这是最直观的思路。题目要求我们找出在
如何判断一个数 pow 函数,即 pow(2.0, x) 完成。
那么 pow(2.0, x),pow(2.0, y) 的结果就会超过 int 类型能容纳的范围而产生错误。
参考代码:
for (________) { // 枚举 l~r 的每一个数
bool flag = false;
for (________) { // 枚举 x
int px = ________; // 计算 2 的 x 次方
for (________) { // 枚举 y
int py = ________; // 计算 2 的 y 次方
if (________) // 判断是否是幂和数
________;
}
}
________; // 更新答案
}
优化一重循环
第一种方法是对每一个数进行“分解”尝试,效率较低。我们可以逆向思考:与其判断一个数能否被凑成,不如我们主动去“凑”出所有的幂和数,然后看它们中有多少个落在了
我们知道,所有的幂和数都由
为了避免重复计数(例如
有的同学可能会觉得,这需要数组(GESP 三级)标记一个数是否会被多次产生。实际上并不需要。重要结论是:一个幂和数,在规定了
for (________) { // 枚举 x
int px = ________; // 计算 2 的 x 次方
for (________) { // 枚举 y
int py = ________; // 计算 2 的 y 次方
if (________) // 判断生成的幂和数是否在 l~r 区间
________
}
}
二进制
知识点:进制(GESP 三级)。
我们来观察一个幂和数
- 如果
x \neq y ,不妨设x > y 。那么2^x 的二进制表示是在第x 位为1 ,其余位为0 ;2^y 的二进制表示是在第y 位为1 ,其余位为0 。由于x \neq y ,这两个数相加时不会产生进位,所以n 的二进制表示中恰好有两位是1 (分别在第x 位和第y 位)。例如,10 = 2^3 + 2^1 ,其二进制为1010,有两个1。 - 如果
x = y ,那么n = 2^x + 2^x = 2^{x+1} 。此时n 本身就是一个2 的幂,它的二进制表示中恰好只有一位是1 。例如,8 = 2^2 + 2^2 = 2^3 ,其二进制为1000,只有一个1。
综上所述,一个正整数
因此,问题被转化为:统计在
在 C++(仅限 GCC 编译器)中,判断一个整数 __builtin_popcount(i) 来高效地完成这个操作。在 C++20(比赛不支持)中,可以使用 std::popcount(i) 函数高效完成这个操作(需要头文件 #include <bit>)。
参考代码:
for (________) {
int p = ________; // 计算二进制表示有多少个 1
if (________)
________; // 统计答案
}