ABC400 C 2^a b^2
翻译
当且仅当一个正整数 \(X\) 满足以下条件时,它才被称为好整数:
- 存在一对正整数 \((a,b)\),使得 \(X=2^a \times b^2\)。
例如,\(400\) 是一个好整数,因为 \(400=2^2 \times 10^2\)。
给定正整数 \(N\),求在 \(1\) 到 \(N\) 之间(包括收尾)的好整数个数。
思路
很容易想出枚举 \(a,b\) 的 \(O(\log N \times \sqrt{N})\) 暴力算法,注意枚举中会出现重复,需要用 map 或 set 记录。
但看到数据范围,很明显会超时,所以思考优化。
首先看能不能优化原式,我们将原式化为 \(X=2^a \times (2^k \times c)^2\),化简得 \(X=2^{a+2k} \times c^2\),其中 \(c\) 为奇数。
由这个式子可以得出,枚举的每一个偶数 \(b\) 都可以由更大的 \(a\) 枚举到的奇数 \(b\) 得到,所以我们就不需要枚举偶数 \(b\) 了。
但是仅凭优化枚举是不够的,其实上一步已经可以得出能够去掉枚举 \(b\) 的循环,我们只需要知道对于现在的 \(a\) 能取到的最大的 \(b\) 是多少就行了,因为只能取奇数所以这次循环能取的值就是 \(\frac{b_{max}}{2}+1\) 。
对于如何取最大的 \(b\),通过式子推导可得 \(b \le \left \lfloor \sqrt{\frac{N}{2^a}} \right \rfloor\),不过我在调代码时发现这里似乎需要精密处理。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m;
int ans;
signed main(){
cin>>n;
for(int a=1;a<=n;a++){//枚举a,这里不用太在意范围,因为后面有退出判断
int p=n>>a;//相当于n/a^2,位运算优化
if(!p) break;//a到上限了
int mxc=sqrt(p);//b
if(mxc*mxc>p) mxc--;
while((mxc+1)*(mxc+1)<=p) mxc++;//这两行代码都是上文提到的精密计算
ans+=(mxc+1)/2;
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号