题解:洛谷 P15798 有限不循环小数
【题目来源】
洛谷:P15798 [GESP202603 五级] 有限不循环小数 - 洛谷
【题目描述】
若 \(\frac{1}{a}\) 可化为一个有限的,不循环的小数,则称 \(a\) 为终止数。
请你求出在 \(L\) 到 \(R\) 中终止数的数量。
【输入】
输入一行,包含两个整数 \(L,R\)。
【输出】
输出一行,包含一个整数,表示 \(L\) 到 \(R\) 中终止数的数量。
【输入样例】
2 11
【输出样例】
5
【核心思想】
-
问题分析:给定区间 \([L, R]\),需要统计其中"终止数"的个数。终止数的定义是:\(\frac{1}{a}\) 可化为有限不循环小数。根据数论知识,一个分数 \(\frac{1}{a}\) 能表示为有限小数,当且仅当分母 \(a\) 的质因数分解中只包含质因子 \(2\) 和 \(5\)(即 \(a = 2^x \times 5^y\),其中 \(x, y \geq 0\))。
-
算法选择:
- 质因子分解判定:对每个数 \(a\),不断除以 \(2\) 和 \(5\),若最终结果为 \(1\),则 \(a\) 是终止数
- 区间枚举:遍历 \([L, R]\) 中的每个整数,调用判定函数筛选
-
关键步骤:
- 判定函数
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\)
- 判定函数
-
时间/空间复杂度:
- 时间复杂度:\(O((R - L + 1) \cdot (\log_2 R + \log_5 R))\),每个数最多被 \(2\) 和 \(5\) 除对数次
- 空间复杂度:\(O(1)\),仅使用常数个变量
-
有限小数判定定理的核心思想:
- 分母决定小数性质:分数 \(\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
浙公网安备 33010602011771号