ABC400 C 2^a b^2

洛谷题面
Atcoder题面
AClink
cnblogs

翻译

当且仅当一个正整数 \(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;
}
posted @ 2025-04-06 10:00  幻琳  阅读(35)  评论(0)    收藏  举报