1642: 【例 2】Fibonacci 第 n 项 时间限制: 1000 ms 内存限制: 524288 KB 提交数: 70 通过数: 22 【题目描述】 大家都知道 Fibonacci 数列吧,f1=1,f2=1,f3=2,f4=3,…,fn=fn−1+fn−2f1=1,f2=1,f3=2,f4=3,…,fn=fn−1+fn−2 。 现在问题很简单,输入 nn 和 mm,求 fnmodmfnmodm。 【输入】 输入 n,mn,m。 【输出】 输出 fnmodmfnmodm。 【输入样例】 5 1000 【输出样例】 5 【提示】 数据范围与提示: 对于 100% 的数据, 1≤n≤2×109,1≤m≤109+101≤n≤2×109,1≤m≤109+10。
由于之前也做过几次Fibonacci数列问题,随手翻了下,看到了一本通网站1642:Fibonacci数列第n项。起初并没有注意这个题是在哪个章节,但看了一下题目,感觉不太难,然后就开始做了。上手后,再细看条件,“对于 100% 的数据, 1≤n≤2×10^9,1≤m≤10^9+10”,这很是要命啊,估计能做到O(n)的时间复杂度都怕是没戏。于是,得思考更高级的时间复杂度算法,初步想到的是O(logn),二分法就是最常见的O(logn)时间复杂度了。那我的想法就集中在f(n)与f(n/2)的关系上了。由于这个题边界条件是两个,f(1)=f(2)=1,估计要直接用f(n/2)表示f(n)是有难度的,还有n可能是一个奇数,也可能是偶数,所以我思考的方向是用两项表示两项:比如用f(3)、f(4)表示f(7)、f(8),再用f(7)、f(8)表示f(15)、f(16)等。为了方便验算,我先求了前面的部分项:f(3)=2,f(4)=3,f(5)=5,f(6)=8,f(7)=13,f(8)=21,f(9)=34,f(10)=55。f(3)=f(2)+f(1),f(4)=f(3)+f(2)=2f(2)+f(1),到这看不出什么特殊性,继续...,f(5)=f(4)+f(3)=2f(3)+f(2), f(6)=f(5)+f(4)=3f(3)+2f(2),有点眉目了,还不明显,再算:f(7)=3f(4)+2f(3),f(8)=3f(5)+2f(4),f(9)=3f(6)+2f(5),f(10)=3f(7)+2f(6),似乎看到f(n+3)=3f(n)+2f(n-1),但不是我们的目标,继续向下:f(8)=5f(4)+3f(3),f(9)=5f(5)+3f(4),f(10)=5f(6)+3f(5)=8f(5)+5f(4),这时可以看到“系数似乎也是数列是的项”,如果是这样,那f(7)=f(4)*f(4)+f(3)*f(3), f(9)=f(4)*f(4)+f(5)*f(5),再验证,没错。偶数呢?f(8)=f(5)*f(4)+f(3)*f(4)=(f(4)+f(3))*f(4)+f(4)*f(3)=f(4)*f(4)+2*f(4)*f(3),f(10)=f(5)*f(5)*2*f(5)*f(4),由此推广可知: f(2n+1)=f(n+1)*f(n+1)+f(n)*f(n),f(2n)=f(n)*f(n)+2*f(n)*f(n-1),二分法基本实现,至于证明,我就不做了,直接上网站提交就知道对大数是否成立了。
不过,还有一个问题,最初我是直接用递归写的程序,但发现会超时,我做了一个跟踪,发现n到1w的时候运算次数就400W次了,所以不能用,于是我想到了记忆递归,直接开个大数组,n的取值是2X10^9,我开了数组a[2e9],编译就报错,开太大了,只好调到a[2e7],部分记忆,还好,能过。
#include<iostream> using namespace std; long long const mxn=20000011; long long n,m,a[mxn]; long long fb(long long n) { if(n==1||n==2)return 1; if(n>=mxn){ long long t1=fb(n/2)%m,t2; if(n%2)t2=fb(n/2+1)%m,t1=(t1*t1+t2*t2)%m; else t2=fb(n/2-1),t1=(t1*t1+2*t1*t2)%m; return t1; } else { if(a[n]==0) { long long t1=fb(n/2)%m,t2; if(n%2)t2=fb(n/2+1)%m,a[n]=(t1*t1+t2*t2)%m; else t2=fb(n/2-1),a[n]=(t1*t1+2*t1*t2)%m; } return a[n]; } } int main() { cin>>n>>m; cout<<fb(n); return 0; }
提交到网站,嘿嘿,过了!
如有不妥,请指教。
后来才看了这一部分属于矩阵,然后拿书出来看了原书解答,真心不懂,需要花点时间去啃这块硬骨头了。