📌  相关文章
📜  Q 查询中位于 [L, R] 范围内的所有回文数的总和(1)

📅  最后修改于: 2023-12-03 15:34:33.351000             🧑  作者: Mango

查询回文数总和

主题

查询中位于 [L, R] 范围内的所有回文数的总和。

介绍

回文数指从左到右和从右到左读取都相同的数字。例如,121、1221、12321 都是回文数。你需要编写一个程序,查询数组中在 [L, R] 范围内的所有回文数的总和。

输入

输入共两行,第一行包含一个整数 Q,表示询问的次数。

接下来 Q 行,每行包含两个整数 L 和 R。

输出

输出共 Q 行,每行包含一个整数,表示对应询问中 [L, R] 范围内的所有回文数的总和。

限制
  • 1 <= Q <= 100000
  • 1 <= L <= R <= 10^9
样例

输入:

3
1 100
1 200
100 200

输出:

20
121
0
算法

本题的算法可分为两个部分:

  1. 枚举回文数
  2. 判断回文数是否在范围内
枚举回文数

考虑如何枚举回文数。一个简单的想法是从 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 的范围很大,直接枚举是不现实的。我们需要通过一些技巧来优化。例如:

  • 使用二分查找
  • 将 L、R 转换成字符串,然后依次比较每一位
  • 将 L、R 分别拆分成两部分,与 num 进行比较
参考实现
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] 范围内。