题解:洛谷 B4497 数数

【题目来源】

洛谷:B4497 [GESP202603 二级] 数数 - 洛谷

【题目描述】

对于正整数 \(n\),如果 \(n\) 的所有数位中包含恰好 \(3\)\(2\),Alice 会认为这个正整数是美丽的。例如,正整数 \(24122\) 中包含 \(3\)\(2\),所以 \(24122\) 是美丽的;正整数 \(132\) 中包含 \(1\)\(2\),所以 \(132\) 不是美丽的;正整数 \(212322\) 中包含 \(4\)\(2\),所以 \(212322\) 不是美丽的。

Alice 想知道正整数 \(L\) 到正整数 \(R\)(包括 \(L\)\(R\))中有多少美丽的正整数,你能帮她数一数吗?

【输入】

输入共 \(2\) 行,第一行为正整数 \(L\),第二行为正整数 \(R\)

【输出】

输出一行,包含一个整数 \(C\),表示 \(L\)\(R\)\(C\) 美丽数的数量。

【输入样例】

2221
2223

【输出样例】

2

【核心思想】

  1. 问题分析:给定区间 \([L, R]\),需要统计其中恰好包含 \(3\) 个数字 \(2\) 的正整数个数。本质是数位特征统计问题,对每个整数逐位检查数字 \(2\) 的出现次数。

  2. 算法选择

    • 逐位分解计数:对每个整数,通过取模和整除操作逐位提取十进制数字,统计数字 \(2\) 的出现次数
    • 区间枚举:遍历 \([L, R]\) 中的每个整数,调用判定函数筛选
  3. 关键步骤

    • 数位统计函数 check(x)
      • 初始化计数器 \(\text{res} = 0\)
      • \(x > 0\) 时循环:
        • \(x \bmod 10 = 2\),则 \(\text{res} \leftarrow \text{res} + 1\)
        • \(x \leftarrow \lfloor x / 10 \rfloor\)(去掉末位)
      • 返回 \(\text{res} = 3\)
    • 主流程
      • 读入 \(L\)\(R\)
      • 遍历 \(i\)\(L\)\(R\):若 check(i) 为真,则 ans++
      • 输出 \(ans\)
  4. 时间/空间复杂度

    • 时间复杂度:\(O((R - L + 1) \cdot \log_{10} R)\),区间长度乘以数字位数
    • 空间复杂度:\(O(1)\),仅使用常数个变量
  5. 逐位分解计数的核心思想

    • 十进制数位提取:利用 \(x \bmod 10\) 获取末位数字,\(x / 10\) 去掉末位,循环直至 \(x = 0\),实现从低位到高位的逐位遍历
    • 精确计数判定:不关注数字的具体排列或数值大小,仅统计目标数字(\(2\))的出现频次,以"恰好 \(3\) 次"作为判定条件
    • 区间暴力枚举:由于数据范围较小(GESP 二级题目),直接枚举区间内所有整数并逐个检查即可,无需数位 DP 等优化
    • 函数封装:将"统计数字 \(2\) 的个数"封装为独立函数 check,主逻辑专注于区间遍历和结果累加,代码结构清晰
    • 适用于数位特征统计、数字模式匹配等基础枚举问题

【算法标签】

入门 #语法基础

【代码详解】

#include <bits/stdc++.h>  // 包含所有标准库头文件
using namespace std;       // 使用标准命名空间

int l, r, ans;  // 定义三个整型变量:l(左边界), r(右边界), ans(结果计数器)

// 判断一个整数是否恰好包含3个数字2
bool check(int x)
{
    int res = 0;  // 计数器,记录数字2出现的次数

    // 逐位检查数字x的每一位
    while (x)
    {
        // 检查当前个位数是否为2
        if (x % 10 == 2)
        {
            res++;  // 如果是2,计数器加1
        }
        x /= 10;  // 去掉当前个位数,继续检查下一位
    }

    // 返回判断结果:数字2是否恰好出现3次
    return res == 3;
}

int main()  // 主函数入口
{
    cin >> l >> r;  // 输入区间范围[l, r]

    // 遍历区间[l, r]中的每一个整数
    for (int i = l; i <= r; i++)
    {
        // 检查当前数字i是否满足条件
        if (check(i))
        {
            ans++;  // 如果满足条件,计数器加1
        }
    }

    cout << ans << endl;  // 输出满足条件的数字个数
    return 0;  // 程序正常结束
}

【运行结果】

2221
2223
2
posted @ 2026-07-01 19:09  团爸讲算法  阅读(12)  评论(0)    收藏  举报