📅  最后修改于: 2023-12-03 15:34:33.351000             🧑  作者: Mango
查询中位于 [L, R] 范围内的所有回文数的总和。
回文数指从左到右和从右到左读取都相同的数字。例如,121、1221、12321 都是回文数。你需要编写一个程序,查询数组中在 [L, R] 范围内的所有回文数的总和。
输入共两行,第一行包含一个整数 Q,表示询问的次数。
接下来 Q 行,每行包含两个整数 L 和 R。
输出共 Q 行,每行包含一个整数,表示对应询问中 [L, R] 范围内的所有回文数的总和。
输入:
3
1 100
1 200
100 200
输出:
20
121
0
本题的算法可分为两个部分:
考虑如何枚举回文数。一个简单的想法是从 1 开始往后枚举,每次将当前数字变成回文数,然后判断是否在范围内。例如,我们从 1 开始往后枚举,得到 1、2、3、4…… 那么怎么将这些数字变成回文数呢?我们需要考虑以下两种情况:
对于偶数位的回文数,我们可以将当前数字拆分成两个相等的部分,然后交换一下顺序就可以得到一个新的回文数。例如,如果当前数字是 1234,我们可以得到 12341234 这个回文数。代码如下:
def even_palindrome(num):
return int(str(num) + str(num)[::-1])
对于奇数位的回文数,我们可以将当前数字拆分成三部分,中间一部分是一个数字,两边的部分是相等的。例如,如果当前数字是 123,我们可以得到 12321 这个回文数。代码如下:
def odd_palindrome(num):
s = str(num)
return int(s + s[:len(s)-1][::-1])
找到所有回文数之后,就需要判断每个回文数是否在 [L, R] 范围内。对于一个数 num,如果它在 [L, R] 范围内,那么它满足 L <= num <= R。由于 L、R 的范围很大,直接枚举是不现实的。我们需要通过一些技巧来优化。例如:
def even_palindrome(num):
return int(str(num) + str(num)[::-1])
def odd_palindrome(num):
s = str(num)
return int(s + s[:len(s)-1][::-1])
def get_range(num, L, R):
if num < L:
return 0
if num > R:
return 0
return num
def binary_search(nums, L, R, num):
left = 0
right = len(nums)
while left < right:
mid = (left + right) // 2
if nums[mid] < num:
left = mid + 1
else:
right = mid
res = 0
for i in range(left, len(nums)):
res += get_range(nums[i], L, R)
return res
def process_query(L, R):
res = 0
# 枚举偶数位回文数
for i in range(1, 100000):
num = even_palindrome(i)
if num > R:
break
res += binary_search(range(num, num+10), L, R, num)
# 枚举奇数位回文数
for i in range(1, 100000):
num = odd_palindrome(i)
if num > R:
break
res += binary_search(range(num, num+10), L, R, num)
return res
q = int(input())
for i in range(q):
L, R = map(int, input().split())
print(process_query(L, R))
以上参考实现采用了二分查找的思路,枚举回文数的过程中,每次枚举一个区间 [num, num+10),然后使用二分查找确定这个区间中有多少个回文数在 [L, R] 范围内。