1 条题解
-
0
题目分析
给定正整数 ,要求用斐波那契数的和或差表示 ,求所需斐波那契数的最小数量。
关键点:允许使用减法,即可以用 或 。
核心思路
1. 贪心策略
对于当前的 ,找到最接近 的斐波那契数 ,然后考虑:
- 用加法:
- 用减法:
选择差值较小的那个方向。
2. 算法流程
- 预处理:生成所有不超过 的斐波那契数
- 对于每个查询:
- 当 时循环:
- 找到大于 的最小斐波那契数位置
id - 计算两种方案的差值:
f[id] - n(减法方案)n - f[id-1](加法方案)
- 选择较小的差值作为新的
- 计数 +1
- 找到大于 的最小斐波那契数位置
- 当 时循环:
- 输出计数结果
代码解析
vector<int> f(2); f[0] = 1, f[1] = 2; // 生成斐波那契数列 while (f[f.size() - 1] <= 400000000000000000ll) f.pb(f[f.size() - 2] + f[f.size() - 1]); int t; cin >> t; while (t--) { int ans = 0, n; cin >> n; while (n) { ++ans; // 二分查找:找到大于n的最小斐波那契数位置 int id = upper_bound(f.begin(), f.end(), n) - f.begin(); // 选择差值较小的方向 n = min(f[id] - n, n - f[id - 1]); } cout << ans << "\n"; }
正确性说明
这种贪心策略的有效性基于斐波那契数列的齐肯多夫定理(Zeckendorf's theorem)的扩展:
- 任何正整数都可以唯一表示为不相邻的斐波那契数之和
- 当允许减法时,可以通过选择最接近的数来快速收敛
复杂度分析
- 预处理:,其中
- 斐波那契数列呈指数增长,项数很少
- 每次查询:
- 每次迭代至少减少到原来的一半
- 每次需要 的二分查找
样例验证
输入:
1 1070处理过程:
- ,最接近的斐波那契数:
- (加法:)
- (减法:) 选择 ,计数=1
- ,最接近:
- (减法:)
- (加法:) 选择 ,计数=2
- ,最接近:
- (加法:)
- (减法:) 选择 ,计数=3
- ,直接使用 ,计数=4
输出:
4
总结
该解法通过贪心+二分巧妙解决了斐波那契表示问题:
- 利用斐波那契数列的指数增长性质
- 每次选择最接近的数,快速收敛
- 时间复杂度优秀,可处理 级别的大数
- 1
信息
- ID
- 3883
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者