题解:洛谷 AT_abc460_a Mod While Positive
【题目来源】
洛谷:AT_abc460_a [ABC460A] Mod While Positive - 洛谷
【题目描述】
给定正整数 \(N\) 和 \(M\)。
当 \(M\not=0\) 时,重复执行以下操作,请计算出操作进行的次数:
- 设 \(x\) 为 \(N\) 除以 \(M\) 的余数。将 \(M\) 的值替换为 \(x\)。
注:可以证明,经过有限次上述操作后,必定会使 \(M=0\)。
【输入】
从标准输入按以下形式给出数据:
\(N\) \(M\)
【输出】
输出答案。
【输入样例】
8 5
【输出样例】
3
【核心思想】
-
问题分析:给定正整数 \(N\) 和 \(M\),模拟辗转相除的过程:不断用 \(N \bmod M\) 替换 \(M\),直到 \(M = 0\),统计操作次数。这是一个辗转相除法(欧几里得算法)的模拟问题,核心在于理解操作序列并正确计数。
-
算法选择:
- 直接模拟:用循环执行取模替换操作,直到 \(M = 0\)
-
关键步骤:
- 读入数据:\(N, M\)
- 循环执行(当 \(M \neq 0\)):
- \(x \leftarrow N \bmod M\)
- \(N \leftarrow M\),\(M \leftarrow x\)
- \(ans \leftarrow ans + 1\)
- 输出结果:\(ans\)
-
时间/空间复杂度:
- 时间复杂度:\(O(\log \min(N, M))\),辗转相除法的步数上界
- 空间复杂度:\(O(1)\)
-
辗转相除模拟的核心思想:
- 操作序列的理解:每次操作为 \(M \leftarrow N \bmod M\),同时 \(N\) 更新为原来的 \(M\)。这与标准欧几里得算法 \(\gcd(N, M) = \gcd(M, N \bmod M)\) 完全一致,只是额外统计了步数
- 终止性保证:由于 \(N \bmod M < M\),每次操作后 \(M\) 严格减小,最终必变为 \(0\)
- 步数计算:循环条件是 \(M \neq 0\),但最后一次操作使 \(M = 0\) 时循环已结束,因此需要额外加 \(1\)。或者更简洁地:循环条件改为 \(M > 0\),每次 \(N \leftarrow M, M \leftarrow N \bmod M\),计数
- 边界注意:代码中
while (n % m != 0)的条件判断的是上一次操作后的余数,因此循环内只统计了"非零余数"的次数,最后需要ans + 1补上最后一次使 \(M = 0\) 的操作 - 适用于基础模拟、欧几里得算法理解类入门问题
【算法标签】
入门 #模拟
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int n, m, ans; // n: 第一个数,m: 第二个数,ans: 步数计数器
int main()
{
cin >> n >> m; // 输入两个正整数
while (n % m != 0) // 当n不能被m整除时循环
{
/// n = n % m; // 错误的写法,应该是m = n % m
m = n % m; // 用n对m取余,更新m
ans++; // 步数加1
}
cout << ans + 1 << endl; // 输出总步数
return 0;
}
【运行结果】
8 5
3
浙公网安备 33010602011771号