蓝桥杯 入门训练 Fibonacci数列

问题描述:
Fibonacci数列的递推公式为:Fn=Fn-1+Fn-2,其中F1=F2=1。
当n比较大,Fn也非常大,现在我们想知道,Fn除以10007的余数是多少。

输入格式:
输入包含一个整数n。

输出格式:
输出一行,包含一个整数,表示Fn除以10007的余数。

说明:在本题中,答案是要求Fn除以10007的余数,因此我们只要能算出这个余数即可,而不需要先计算出Fn的准确值,再将计算的结果除以10007取余数,直接计算余数往往比先算出原数再取余简单。

样例输入
10
样例输出
55
样例输入
22
样例输出
7704
数据规模与约定
1 <= n <= 1,000,000。

解决问题的核心是用了一个取余运算的公式: (a + b) % x = (a % x + b % x) % x

斐波那契数列的递推公式为 Fn = Fn-1 + Fn-2 ,现在要对Fn取余, 根据上述取余运算的公式,就等价于对(Fn-1 % x + Fn-2 % x)。 (要对Fn取余,就对Fn-1和Fn-2各自取余之和再取余。)

所以,只要把斐波那契数列的每一项做个转换就行了: 原来的数列,每一项是前两项之和,而现在变成每一项是前两项之和取余,就能解决问题了。(每一项都是个余数)
如“说明”中所讲,不用求出具体的斐波那契数到底是多少。如果把每一个斐波那契数都求出来然后在取余,一是时间不够,二是类型会溢出。
下面是转换前后的斐波那契数列的示例:

Nth12345181920212223
11235258441816765109461771128657
1123525844181676593977048643

下面是代码: MyGithub

大段的注释可忽略

#include<stdio.h>
/*
// 求斐波那契数列的比递归快的方法,
// 但当n很大时,会溢出。
long fib(long n) {
    long a = 1, b = 1;
    if(n <= 2) {
        return 1;
    }
    else {
        long f;
        long i;
        for(i = 3;i <= n;i++) {
            f = a + b;
            a = b;
            b = f;
        }
        return f;
    }
}
*/
int main() {
    long num, i;
    scanf("%d", &num);
    int a = 1, b = 1, f;
    if(num<=2) {
        printf("%d\n", 1);
    }
    else {
        for(i=3;i<=num;i++) {
                f = (a + b) % 10007; // 使从第三项起的每一项都变成余数
                a = b;
                b = f;
        }
        printf("%d\n", f);
    }
    return 0;
}

Email: [email protected]
GitHub: liberty1997

点赞