【题解】AtCoder AT_abc400_c 2^a b^2

题目大意

我们定义满足下面条件的整数 X X X 为“好整数”:

  • 存在一个 正整数 ( a , b ) (a,b) (a,b) 使得 X = 2 a ⋅ b 2 X=2^a\cdot b^2 X=2ab2
    给定一个正整数 N N N 1 ≤ N ≤ 1 0 18 1\le N\le 10^{18} 1N1018),求 1 ∼ N 1\sim N 1N 中有多少“好整数”。

思路

下面是一张表格,第一列的数表示 a a a 的值,第一行表示 b b b 的值,第 x x x 列第 y y y 行的数表示 2 x ⋅ y 2 2^x\cdot y^2 2xy2 的值。

a \ b 1 2 3 4
1 2 8 18 32
2 4 16 36 64
3 8 32 72 128
4 16 64 144 256

观察可得, 2 1 × 4 2 = 2 3 × 2 2 ,   2 2 × 4 2 = 2 4 × 4 2 2^1\times 4^2=2^3\times2^2,\ 2^2\times4^2=2^4\times 4^2 21×42=23×22, 22×42=24×42,这的确是交换率的体现,但是我们仔细思考会发现,当 b b b 是二的倍数的时候,无论 a a a 取多少,都会有另一对 ( a ′ , b ′ ) (a',b') (a,b) 满足 2 a ′ ⋅ b ′ 2 = 2 a ⋅ b 2 2^{a'}\cdot {b'}^2=2^a\cdot b^2 2ab2=2ab2

那么我们可以基于这个规律来减少枚举次数:枚举 b b b 的值,只需要枚举 1 ∼ ⌊ N ⌋ 1\sim \left \lfloor \sqrt{N}\right \rfloor 1N 的所有 奇数;然后枚举所有满足 2 a ⋅ b 2 ≤ N 2^a\cdot b^2\le N 2ab2N a a a。这种做法不但快捷,还可以保证不重不漏,可以在规定时间内输出正确的答案。

代码

赛时提交记录(含有一些多余内容):Submission #64615650。

#include 
#include 
#include 
using namespace std;
typedef long long LL;

LL n, ans;

int main()
{
	cin >> n;
	for (LL i = 2; i <= n; i *= 2) ans++;
	for (LL i = 3; i * i * 2 <= n; i += 2)
		for (LL j = 2; i * i * j <= n; j *= 2)
			ans++;
	cout << ans << endl;
	return 0;
}

总结

这是一道数学思维题,难度与比赛分值 350 分相符。希望这篇题解对你有帮助,如有想法欢迎在评论区提出!

你可能感兴趣的:(AtCoder,数学思维)