题面数列从 0 开始,第 n 项就是零起编号的 F(n-1);用记忆化递归按递推式求,每个下标只算一次。
OJ: roj
题目 ID: 1159
难度:入门
标签:入门递推数学递归python
创建: 2026-09-29 21:26
更新: 2026-10-05 03:50
题目描述
题面数列为
输入:一个正整数 3,输出 1(注意数列首项是
思路
按定义
参考代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-09-29 21:26
# update_at: 2026-09-29 21:30
import sys
from functools import cache
@cache
def fib_pair(n: int) -> tuple[int, int]:
"""返回 (F(n), F(n+1)),其中 F(0)=0、F(1)=1。
倍增恒等式:F(2m)=F(m)·(2F(m+1)−F(m)),F(2m+1)=F(m)²+F(m+1)²。
把下标折半就能一次拿到相邻两项 F(2m)、F(2m+1),递归深度只有 O(log n)。
"""
if n < 2: # 边界:(F(0),F(1))=(0,1),(F(1),F(2))=(1,1)——第二项恒为 1
return n, 1
lo, hi = fib_pair(n >> 1) # 下标折半,m = ⌊n/2⌋
even = lo * (2 * hi - lo) # F(2m)
odd = lo * lo + hi * hi # F(2m+1)
return (odd, even + odd) if n & 1 else (even, odd) # 奇数时再向前迈一步
def solve() -> None:
n = int(sys.stdin.buffer.read())
# 题面数列 0,1,1,2,3,5,... 是零起编号的斐波那契:第 n 项就是 F(n-1)
print(fib_pair(n - 1)[0])
if __name__ == "__main__":
solve()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-05 03:50
* update_at: 2026-10-05 03:50
*/
#include <cstdio>
typedef long long ll;
ll n; // 输入的项号
ll fib_value[105]; // fib_value[i] = 零起编号斐波那契 F(i),F(0)=0、F(1)=1
char computed[105]; // computed[i] 标记 F(i) 是否已经算过,只有 0/1,用 char 省内存
// 记忆化递归:返回 F(i),每个下标只计算一次
ll fib(ll i) {
if (i < 2) return i;
if (computed[i]) return fib_value[i];
fib_value[i] = fib(i - 1) + fib(i - 2);
computed[i] = 1;
return fib_value[i];
}
int main() {
scanf("%lld", &n);
// 题面数列 0,1,1,2,3,5,... 首项是 0,第 n 项对应零起编号的 F(n-1)
printf("%lld\n", fib(n - 1));
return 0;
}