[信息与未来 2023] 幸运数字 的题解


记住只在没有思路时使用题解,不要从它复制粘贴代码。请尊重题目和题解的作者。
在解题之前提交题解的代码会导致封禁。

作者: admin

概述

本题要求统计区间 [a, b] 内十进制表示的奇数位数字和与偶数位数字和相等的幸运数字个数。核心解法是直接枚举区间内每个数并检查其奇数位、偶数位数字和是否相等;由于 b \le 10^6,枚举完全可行。

分析
核心观察

幸运数字只取决于各位数字本身,检查一个数只需 O(\log_{10} x) 次运算;数据范围 b \le 10^6 使直接枚举区间内所有数即可在时限内完成。

思路

对区间内每个整数 x,按从左到右的位置(第 1, 3, 5, \ldots 位为奇数位,第 2, 4, \ldots 位为偶数位)将十进制位分成两组,分别求和,若相等则计数加 1。注意从右往左编号得到的分组与此等价(偶数位长度时两组互换,但相等条件对称),因此按从左编号即可。

枚举总代价为 O((b - a) \log_{10} b),在 b \le 10^6 时约 7 \times 10^6 次运算,足够快;若数据范围更大,可改用数位 DP 在 O(\log b) 内求出前缀计数。

具体示例

以样例 1 为例:[1, 100] 中,一位数 1 \sim 9 的奇数位和等于其本身而偶数位和为 0,均不幸运;两位数中形如 11, 22, \ldots, 99 的数幸运,共 9 个;100 的奇数位和 1 + 0 = 1 不等于偶数位和 0。总计 9 个,与样例一致。

算法步骤
  1. 读入 a、b,令计数器 cnt 为 0。
  2. 枚举 x 从 a 到 b:
    • 将 x 转为十进制字符串,按位置把各位数字分别累加到奇数位和 odd 与偶数位和 even;
    • 若 odd 等于 even,cnt 加 1。
  3. 输出 cnt。
复杂度分析

时间:O((b - a) \log_{10} b)

空间:O(1)

实现注意事项
  • 位置从 1 开始编号,如 12345 的奇数位是第 1, 3, 5 位(数字 1, 3, 5)。
  • 一位数的偶数位和为 0,只有数字本身为 0 时才可能相等;本题区间从 a \ge 1 开始,不受影响。
  • 枚举次数最多 10^6,也可用除法和取模逐位提取数字以避免字符串转换开销。
源代码
#include <bits/stdc++.h>
using namespace std;

int main() {
    int a, b;
    cin >> a >> b;

    int cnt = 0;
    for (int x = a; x <= b; x++) {
        string s = to_string(x);
        int odd = 0, even = 0;
        for (int i = 0; i < (int)s.size(); i++) {
            if (i % 2 == 0) odd += s[i] - '0';
            else even += s[i] - '0';
        }
        if (odd == even) cnt++;
    }
    cout << cnt << '\n';
    return 0;
}
a, b = map(int, input().split())

def is_lucky(x):
    s = str(x)
    odd = sum(int(c) for i, c in enumerate(s) if i % 2 == 0)
    even = sum(int(c) for i, c in enumerate(s) if i % 2 == 1)
    return odd == even

print(sum(1 for x in range(a, b + 1) if is_lucky(x)))

评论

目前没有评论。