题解:洛谷 P15798 有限不循环小数

【题目来源】

洛谷:P15798 [GESP202603 五级] 有限不循环小数 - 洛谷

【题目描述】

\(\frac{1}{a}\) 可化为一个有限的,不循环的小数,则称 \(a\)终止数

请你求出在 \(L\)\(R\) 中终止数的数量。

【输入】

输入一行,包含两个整数 \(L,R\)

【输出】

输出一行,包含一个整数,表示 \(L\)\(R\) 中终止数的数量。

【输入样例】

2 11

【输出样例】

5

【核心思想】

  1. 问题分析:给定区间 \([L, R]\),需要统计其中"终止数"的个数。终止数的定义是:\(\frac{1}{a}\) 可化为有限不循环小数。根据数论知识,一个分数 \(\frac{1}{a}\) 能表示为有限小数,当且仅当分母 \(a\) 的质因数分解中只包含质因子 \(2\)\(5\)(即 \(a = 2^x \times 5^y\),其中 \(x, y \geq 0\))。

  2. 算法选择

    • 质因子分解判定:对每个数 \(a\),不断除以 \(2\)\(5\),若最终结果为 \(1\),则 \(a\) 是终止数
    • 区间枚举:遍历 \([L, R]\) 中的每个整数,调用判定函数筛选
  3. 关键步骤

    • 判定函数 check(x)
      • \(x \bmod 2 = 0\) 时,\(x \leftarrow x / 2\)(去除所有因子 \(2\)
      • \(x \bmod 5 = 0\) 时,\(x \leftarrow x / 5\)(去除所有因子 \(5\)
      • 返回 \(x = 1\)(若剩余为 \(1\) 说明仅含因子 \(2\)\(5\)
    • 主流程
      • 读入 \(L\)\(R\)
      • 遍历 \(i\)\(L\)\(R\):若 check(i) 为真,则 ans++
      • 输出 \(ans\)
  4. 时间/空间复杂度

    • 时间复杂度:\(O((R - L + 1) \cdot (\log_2 R + \log_5 R))\),每个数最多被 \(2\)\(5\) 除对数次
    • 空间复杂度:\(O(1)\),仅使用常数个变量
  5. 有限小数判定定理的核心思想

    • 分母决定小数性质:分数 \(\frac{p}{q}\)(最简形式)能化为有限小数,当且仅当分母 \(q\) 的质因数只含 \(2\)\(5\)。这是因为十进制有限小数的分母必为 \(10^k = 2^k \times 5^k\) 的因数
    • 因子剥离法:通过反复除以 \(2\)\(5\),将 \(a\) 中所有"合法"质因子去除,若剩余大于 \(1\),则存在其他质因子(如 \(3, 7, 11\) 等),判定为非终止数
    • 贪心除尽策略:先除尽所有 \(2\) 再除尽所有 \(5\)(或顺序相反),由于 \(2\)\(5\) 互质,顺序不影响最终结果
    • 数学定理的工程化:将"有限小数判定"这一数论定理转化为简单的循环除法操作,避免了完整的质因数分解
    • 适用于数论性质判定、质因子筛选、小数分类等基础数学问题

【算法标签】

普及- #约数

【代码详解】

#include <bits/stdc++.h>
using namespace std;
int l, r, ans;

// 检查一个数是否只包含质因子 2 和 5
bool check(int x)
{
    // 不断除以 2
    while (x % 2 == 0)
    {
        x /= 2;
    }

    // 不断除以 5
    while (x % 5 == 0)
    {
        x /= 5;
    }

    // 如果最终结果为 1,说明 x 只包含质因子 2 和 5
    return x == 1;
}

int main()
{
    cin >> l >> r;

    // 遍历区间 [l, r] 中的每个数
    for (int i = l; i <= r; i++)
    {
        if (check(i))
        {
            ans++;
        }
    }

    cout << ans << endl;
    return 0;
}

【运行结果】

2 11
5
posted @ 2026-07-01 21:37  团爸讲算法  阅读(16)  评论(0)    收藏  举报