1 条题解
-
0
题目解析
问题重述
初始有一枚价值为 的硬币。每次操作可以选择一枚价值 的硬币,将其替换为两枚价值为 的硬币。问经过任意次操作后,最多能获得多少枚硬币。
核心思路
1. 贪心策略
由于每次操作都会增加硬币总数( 枚变成 枚),只要存在价值 的硬币,我们就应该进行操作。因为操作只会让硬币价值变小,不会产生负面影响,且能增加数量。
2. 批量操作优化
如果一枚价值为 的硬币可以进行 次操作,那么:
- 第 次操作后: 枚价值 的硬币
- 第 次操作后: 枚价值 的硬币
- 第 次操作后: 枚价值 的硬币
- ……
- 第 次操作后: 枚价值 的硬币
因此,我们不需要模拟每次操作处理一枚硬币,而是可以一次性处理所有同价值的硬币。
3. 算法流程
设当前硬币价值为 ,硬币数量为 :
- 初始:,
- 当 时:
- 将所有价值为 的硬币各操作一次
- 每枚价值 的硬币变成 枚价值 的硬币
- 因此:,
- 最终答案为
这个过程可以用一个简单循环实现:
ans = 1 while n > 3: n //= 4 ans *= 24. 数学公式
设 为满足 的最小整数,即不断除以 直到值 的次数。
则答案为:
其中 ,即 。
注意: 使用浮点数对数函数可能产生精度问题,因为 最大为 ,浮点数精度不足以精确表示。推荐使用迭代或二分法求 。
示例验证
示例1:
- ,循环不执行
- ✅
示例2:
- 第1次:,
- ,停止
- ✅
示例3:
- 第1次:,
- 第2次:,
- ,停止
- ✅
示例4:
- 循环执行 次
- ✅
时间复杂度
- 每次循环 除以 ,最多 次
- 时,最多约 次循环
- ,总操作次数约 ,非常快
注意事项
- 数据类型: 使用
long long存储 ,因为 超出int范围 - 避免浮点数: 不要使用
log()函数,可能产生精度误差 - 循环条件:
while (n > 3)而不是while (n > 0),因为 时无法操作
公式推导
从递推式出发:
$$f(x) = \begin{cases} 1 & x \le 3 \\ 2 \cdot f(\lfloor x/4 \rfloor) & x > 3 \end{cases}$$展开得:
$$f(n) = 2 \cdot f(\lfloor n/4 \rfloor) = 2^2 \cdot f(\lfloor n/16 \rfloor) = \cdots = 2^k \cdot f(\lfloor n/4^k \rfloor) $$当 时,,此时 。
所以 ,。
C++ 代码
#include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { long long n; cin >> n; long long ans = 1; while (n > 3) { n /= 4; // 价值变为原来的 1/4 ans *= 2; // 硬币数量翻倍 } cout << ans << '\n'; } return 0; }递归版本(仅供参考)
#include <bits/stdc++.h> using namespace std; long long solve(long long n) { if (n <= 3) return 1; return 2 * solve(n / 4); } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { long long n; cin >> n; cout << solve(n) << '\n'; } return 0; }二分查找版本(求 )
#include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { long long n; cin >> n; // 二分查找最大的 k 使得 4^k <= n int k = 0; long long p = 1; // p = 4^k while (p * 4 <= n) { p *= 4; k++; } // 或者直接用循环计算 // int k = 0; // while ((1LL << (2 * k)) <= n) k++; // 4^k = 2^(2k) // k--; // 调整 long long ans = 1LL << k; // 2^k cout << ans << '\n'; } return 0; }关键点总结
- 贪心正确性: 只要 ,操作一定增加硬币数,且不会阻碍后续操作
- 批量处理: 所有同价值硬币可以同时操作,简化模拟过程
- 循环次数: 约 次,非常高效
- 整数运算: 全程使用整数除法和乘法,避免浮点数精度问题
- 边界条件: 时无法操作,答案为
- 1
信息
- ID
- 7061
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 2
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者