NYOJ「完全平方數的個數」:給定區間 [A, B] (1 ≤ A ≤ B ≤ 2×10⁹),求區間內完全平方數個數。本文推導 O(1) 數學公式,避免遍歷。
完全平方數為 k²。k² ∈ [A, B] ⇔ k ∈ [⌈√A⌉, ⌊√B⌋]。
個數 = ⌊√B⌋ - ⌈√A⌉ + 1 = ⌊√B⌋ - ⌊√(A-1)⌋。
⌊√B⌋(即 1², 2², ..., ⌊√B⌋²)。⌊√(A-1)⌋。#include <cstdio>
#include <cmath>
using namespace std;
int main() {
long long A, B;
while (scanf("%lld%lld", &A, &B) == 2) {
long long cnt = (long long)sqrt(B) - (long long)sqrt(A - 1);
printf("%lld\n", cnt);
}
return 0;
}
(long long)sqrt(x) 等價於 floor(sqrt(x))(對非負數)。sqrt(25) 可能得 4.9999999,截斷為 4。修正:long long isqrt(long long x) {
long long r = sqrt((double)x);
while ((r+1)*(r+1) <= x) ++r;
while (r*r > x) --r;
return r;
}
// 使用 isqrt(B) - isqrt(A-1) 絕對安全
| A | B | √B | √(A-1) | 答案 | 說明 |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 0 | 1 | 1²=1 |
| 1 | 2 | 1 | 0 | 1 | 1²=1 |
| 3 | 10 | 3 | 1 | 2 | 2²=4, 3²=9 |
| 3 | 3 | 1 | 1 | 0 | 無平方數 |
| 1000000000000000000 | 1000000000000000000 | 1000000000 | 999999999 | 1 | 10¹⁸=(10⁹)² |
本題是數學洞察力的直接考察:區間內平方數個數 = ⌊√B⌋ - ⌊√(A-1)⌋。代碼極短,關鍵在於理解公式推導並處理浮點精度邊界。競賽中直接用 sqrt + 截斷通常能過,嚴謹場景建議用整數二分法實現 isqrt。