1. 从递推数列到模周期:一道ACM入门题的深度解析
作为一名曾经的ACM选手,看到这道题让我想起了自己大一时的青涩时光。这道看似简单的递推数列问题,其实蕴含着算法竞赛中两个非常重要的思维模式:暴力解法优化与数学规律挖掘。让我们一起来拆解这个问题的多种解法,并探讨如何从算法小白成长为竞赛选手的路径。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 问题重述与初步分析
2.1 题目定义
我们有一个递推数列定义如下:
- f(0) = 7
- f(1) = 11
- 递推公式:f(n) = f(n-1) + f(n-2) (n≥2)
给定一个正整数N (0≤N≤1e18),需要判断f(N)是否能被3整除。如果整除输出"yes",否则输出"no"。
2.2 输入输出要求
标准的ACM竞赛输入格式,多组测试数据,每组数据一个整数N,直到输入结束。对于每个N,输出对应的判断结果。
3. 暴力解法及其局限性
3.1 递归暴力解法
最直观的想法是直接计算f(N)的值,然后判断是否能被3整除。递归实现如下:
cpp复制int fib_mod(int n) {
if(n == 0) return 7;
if(n == 1) return 11;
return fib_mod(n-1) + fib_mod(n-2);
}
这种解法的问题在于:
- 递归深度随N指数增长,导致栈溢出
- 重复计算严重,时间复杂度O(2^N)
- 当N很大时,计算时间不可接受
3.2 迭代暴力解法
改进为迭代方式可以避免栈溢出问题:
cpp复制int fib_mod(int n) {
if(n == 0) return 7;
if(n == 1) return 11;
int n1 = 7;
int n2 = 11;
for(int i = 2; i <= n; ++i) {
int temp = n1 + n2;
n1 = n2;
n2 = temp;
}
return n2;
}
虽然解决了栈溢出问题,但当N=1e18时,循环次数高达1e18次,仍然无法在合理时间内完成计算。
提示:在ACM竞赛中,1秒
