准备蓝桥杯也有一段时间了,今天开始准备把做过的有学到一点东西的题目记录下来,以便日后翻阅。
入门训练 Fibonacci数列
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
Fibonacci数列的递推公式为:Fn=Fn-1+Fn-2,其中F1=F2=1。
当n比较大时,Fn也非常大,现在我们想知道,Fn除以10007的余数是多少。
输入格式
输入包含一个整数n。
输出格式
输出一行,包含一个整数,表示Fn除以10007的余数。
样例输入
10
22
样例输出
55
7704
数据规模与约定
1 <= n <= 1,000,000。
刚刚拿到题目的时候没有注意到资源的要求,于是直接写了递归算法提交:
`#include <iostream>
using namespace std;
long F(long n){
if(n==1 || n==2)
return 1;
else
return F(n-1)+F(n-2);
}
int main(){
long n;
cin>>n;
cout<<F(n)%10007<<endl;
}
`
结果当然是运行超时:
递归算法在相对较小的范围内还是很实用的,但是在n取到40左右的数字时运行时间就有些长了,一百万的时候就更不用说了。在网络上寻找相关解题方法的时候发现了下面的解法:
#include <iostream>
using namespace std;
int main(){
int a1=1,a2=1;
int temp;
long n;
cin>>n;
for(long i=1;i<n;i++){
temp=a2;
a2=(a1+a2)%10007;
a1=temp;
}
cout<<a1<<endl;
return 0;
}
我尝试了很多次去理解这段代码,但是最终也没有完全搞明白。看到有人说其实是使用了余数的加法定理,才稍微有了些头绪。
余数的加法定理:a与b的和除以c的余数,等于a,b分别除以c的余数之和,或这个和除以c的余数。即(a+b)%c=(a%c+b%c)%c。
虽然没搞明白,但是这种方法毫无疑问是接近最佳答案的,它的CPU时间为0ms,内存使用仅为2.449MB。
之后我又想到使用数组来存放每一个Fn%10007的结果,输入n后直接读取也可以解决问题。
#include <iostream>
using namespace std;
long long a[1000000];
void Fibo(){
a[0]=0;
a[1]=a[2]=1;
for(int i=3;i<=1000000;i++){
a[i]=(a[i-1]+a[i-2])%10007;
}
}
int main(){
long n;
cin>>n;
Fibo();
cout<<a[n]<<endl;
return 0;
}
这种方法的两项指标都比上一种差,但是更容易理解(也许是我太菜了理解不来上一种的原因┭┮﹏┭┮)。
入门训练的四道题目难度都不大,但是确实把需要注意的点都顾及到了,算是基础中的基础吧。
第一次写浪费了太多时间在小细节上,但总算是把做题时的想法都顾及到了。之后遇到值得记录的题目再继续写叭。