1 条题解
-
0
A. 求最少操作次数 - 详细题解
问题重述
给定两个整数 和 ,每次操作可以减去 的任意非负整数次幂(即 )。求将 变为 所需的最少操作次数。
关键观察
观察 1: 的特殊情况
当 时, 的幂次只有 。因此每次只能减去 ,最少操作次数为:
观察 2:模 的视角
考虑对 取模。任何 ()都是 的倍数,因此:
而 ,所以:
因此,只有减去 的操作会改变 模 的值。
观察 3:处理余数
设 ,其中 。
为了将 变为 ( 是 的倍数),我们需要消除余数 。
由于只有减去 才能改变余数,我们必须执行 次减去 的操作,使 变为 的倍数:
这 次操作是必须的。
观察 4:转化为子问题
现在 是 的倍数。考虑以下两种策略:
策略 A:继续减去 ()
- 减去 后, 变为 ,余数变为
- 需要再减去 次 才能回到 的倍数
- 总共 次操作,效果相当于减去 (即减去 一次)
策略 B:直接减去
- 一次操作, 变为
显然,策略 B 更优( 次操作 vs 次操作)。
因此,当 是 的倍数时,最优策略是不断减去 本身,相当于将问题规模缩小为 。
观察 5:递归/迭代过程
将上述过程形式化:
- 设当前值为
- 若 ,结束
- 否则,取 ,需要 次减去 的操作
- 然后令 ,重复步骤 2-4
这实际上就是将 表示为 进制数,然后求各位数字之和。
数学证明
设 的 进制表示为:
$$n = d_0 + d_1 \cdot k + d_2 \cdot k^2 + \cdots + d_m \cdot k^m $$其中 。
- 是 ,需要 次减去 的操作
- 减去 个 后, 变为
- 然后可以用一次减去 的操作替代 次减去 的操作
- 这等价于将 除以 后继续处理
因此,最少操作次数为:
$$\text{ans} = d_0 + d_1 + d_2 + \cdots + d_m = \sum_{i=0}^{m} d_i $$即 在 进制下的各位数字之和。
算法步骤
- 如果 ,直接输出
- 否则,初始化
- 当 时:
- 输出
完整代码
#include <bits/stdc++.h> using namespace std; int find_min_operations(int n, int k) { if (k == 1) return n; int ans = 0; while (n > 0) { ans += n % k; n /= k; } return ans; } int main() { ios_base::sync_with_stdio(false); cin.tie(0); int t; cin >> t; while (t--) { int n, k; cin >> n >> k; cout << find_min_operations(n, k) << "\n"; } return 0; }
时间复杂度
- 每个测试用例:
- 总复杂度:,其中
示例验证
测试用例 1:
的二进制表示为 ,各位数字和
输出: ✓
测试用例 2:
的五进制表示为 ,各位数字和
输出: ✓
测试用例 3:
的四进制表示为 ,各位数字和
输出: ✓
测试用例 4:
的三进制表示: 余 , 余 , 余 , 余 , 余
得到数字:,从低位到高位:
各位数字和
输出: ✓
测试用例 5:
的十进制各位数字和
输出: ✓
测试用例 6:
,直接输出
输出: ✓
关键公式总结
$$\boxed{\text{最少操作次数} = \text{将 } n \text{ 表示为 } k \text{ 进制后的各位数字之和}} $$
- 1
信息
- ID
- 6333
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 2
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者