題目的難度顏色使用 Luogu 上的分級,由簡單到困難分別為 🔴🟠🟡🟢🔵🟣⚫。
Problem Statement
題目簡述
定義 f(x,y) 為將正整數 x 和 y 的十進位表示串接後得到的整數(例如 f(3,14)=314)。
給定正整數 C 和 D,求滿足 1≤x≤D 且 f(C,C+x) 為完全平方數的 x 的個數
Constraints
約束條件
- 1≤C≤2×108
- 1≤D≤5×109
思路:按位數分段枚舉 + 區間完全平方數計數
問題轉化
令 y=C+x,則 x∈[1,D] 等價於 y∈[C+1,C+D]。
串接函數 f(C,y) 的數學意義:若 y 的十進位有 ℓ 位,則
f(C,y)=C⋅10ℓ+y
問題變成:有多少 y∈[C+1,C+D] 使得 C⋅10ℓ+y 為完全平方數?
固定位數後的區間計數
對於固定的位數 ℓ,y 的範圍為 [10ℓ−1,10ℓ−1](即所有 ℓ 位正整數)。將此範圍與 [C+1,C+D] 取交集,得到有效的 y 範圍 [lo,hi]。
此時 f(C,y)=C⋅10ℓ+y 隨 y 單調遞增,所以目標值的範圍也是一段連續區間:
L=C⋅10ℓ+lo,R=C⋅10ℓ+hi
問題最終歸結為:[L,R] 中有多少個完全平方數?
區間完全平方數計數
[L,R] 中的完全平方數個數 =⌊R⌋−⌈L⌉+1(若結果為負則為 0)。
其中:
- kmax=⌊R⌋:用
isqrt(R) 計算
- kmin=⌈L⌉:用
isqrt(L - 1) + 1 計算(因為 ⌈L⌉=⌊L−1⌋+1 對非完全平方的 L 成立,而對完全平方的 L 也是正確的)
直接使用浮點數的 math.sqrt 會有精度問題(C⋅10ℓ+y 可達約 2×1018),必須使用 Python 的 math.isqrt(整數精確平方根)。
枚舉位數的範圍
y 的最小值為 C+1,最大值為 C+D,因此 ℓ 的範圍為 [len(C+1),len(C+D)]。由於 C≤2×108、D≤5×109,y 最大約為 5.2×109,所以 ℓ 最多為 10,枚舉量極小。
對每組測資,枚舉 y 的位數 ℓ(至多約 10 種),對每個 ℓ 計算有效 y 範圍並用整數平方根求區間內完全平方數個數,累加即為答案。每組測資 O(log(C+D))。
複雜度分析
- 時間複雜度:O(T⋅log10(C+D))
- 空間複雜度:O(log10(C+D))(預處理 10 的冪次表)
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| from math import isqrt
pow10 = [1] for _ in range(1, 20): pow10.append(pow10[-1] * 10)
def solve(): C, D = map(int, input().split())
ans = 0 for ln in range(len(str(C + 1)), len(str(C + D)) + 1): lo = max(C + 1, pow10[ln - 1]) hi = min(C + D, pow10[ln] - 1) if lo > hi: continue L = C * pow10[ln] + lo R = C * pow10[ln] + hi k_max = isqrt(R) k_min = isqrt(L - 1) + 1 ans += max(0, k_max - k_min + 1)
print(ans)
if __name__ == "__main__": t = int(input()) for _ in range(t): solve()
|