zoukankan      html  css  js  c++  java
  • 算法设计与分析 1.2 不一样的fibonacci数列 (矩阵快速幂思想)

    题目描述

    Winder 最近在学习 fibonacci 数列的相关知识。我们都知道 fibonacci 数列的递推公式是F(n) = F(n - 1) + F(n - 2)(n >= 2 且 n 为整数)。

    Winder 想知道的是当我们将这个递推式改为F(n) = a * F(n - 1) + b * F(n - 2)(n >= 2 且 n 为整数)时我们得到的是怎样的数列。但是,Winder 很懒,所以只能由你来帮他来完成这件事。

    注意,这里我们依然令 F(0)=F(1)=1。

    输入格式

    输入第一行三个正整数 q, a, b。

    接下来有 q 行,每行一个自然数 n。

    对于50%的数据,1 <= q、n <= 1000。

    对于80%的数据,1 <= q、n <= 100000。

    对于100%的数据,1 <= q <= 100000,1 <= n <= 1000000000,1 <= a、b <= 1000。

    输出格式

    输出一行一个整数 F(n),由于结果可能会很大,Winder 要求输出结果对 2013 取模,即将 F(n)对2013求余后输出。

    样例输入

    5 4 5
    2
    4
    8
    16
    32
    

    样例输出

    9
    209
    1377
    182
    9


    方法一:

    刚开始拿到题目的时候第一反应是按要求做一个递归算法,但是后来发现递归的代价太大,可能会过不了。

    方法二:

    和方法一一个思路,但是使用了非递归算法,虽然肯定不是最优算法,但是应该可以得一个基础分了。

    #include <iostream>
    using namespace std;
    int fibonacci(int n, int a, int b)
    {
           if (n <= 1)
                  return 1;
           else
           {
                  int current = 0;
                  int pre1 = 1;
                  int pre2 = 1;
                  for (int i = 2; i <= n; i++)
                  {
                         current = (a * pre1 + b * pre2) % 2013;
                         pre2 = pre1;
                         pre1 = current;
                  }
                  return current;
           }
    }
    int main()
    {
           int q, a, b;
           cin >> q >> a >> b;
           int *result = new int[q];
           for (int i = 0; i < q; i++) {
                  int n;
                  cin >> n;
                  result[i] = fibonacci(n, a, b);
           }
           for (int i = 0; i < q; i++) {
                  cout << result[i] << endl;
           }
           delete[]result;
           return 0;
    }

    方法三:

    这个是在理解了矩阵快速幂的思想基础上,进行改进的一个算法,把问题规模直接降了一大截。

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <iostream>
    using namespace std;
    const int MOD = 2013;
     
    struct matrix {     //矩阵 
        int m[2][2];
    }ans;
     
    matrix multi(matrix a, matrix b) {  //矩阵相乘,返回一个矩阵 
        matrix tmp;
        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 2; j++) {
                tmp.m[i][j] = 0;
                for (int k = 0; k < 2; k++)
                    tmp.m[i][j] = (tmp.m[i][j] + a.m[i][k] * b.m[k][j]) % MOD;
            }
        }
        return tmp;
    }
     
    matrix matrix_pow(matrix a, int n) {   //矩阵快速幂,矩阵a的n次幂 
        ans.m[0][0] = ans.m[1][1] = 1;  //初始化为单位矩阵 
        ans.m[0][1] = ans.m[1][0] = 0;
        while (n) {
            if (n & 1) ans = multi(ans, a);
            a = multi(a, a);
            n >>= 1;
        }
        return ans;
    }
     
    int main() {
        int q, n, a, b;
        cin >> q >> a >> b;
        int* result = new int[q];
        matrix mul;
        mul.m[0][0] = a;
        mul.m[0][1] = b;
        mul.m[1][0] = 1;
        mul.m[1][1] = 0;
        for (int i = 0; i < q; i++) {
            int n;
            cin >> n;
            matrix mm = matrix_pow(mul, n - 1);
            result[i] = (mm.m[0][0] + mm.m[0][1])%MOD;
        }
        for (int i = 0; i < q; i++) {
            cout << result[i] << endl;
        }
        delete[]result;
        return 0;
    }

    第一次做的时候因为最后一步的时候在result[i] = (mm.m[0][0] + mm.m[0][1])%MOD的时候忘记

    了加这个“%MOD”,导致结果一直有部分不对,调试了将近一个上午(好惨)。

  • 相关阅读:
    调研一类软件的发展演变—聊天软件( 1000-2000 words, in Chinese)
    C++用法的学习心得(要求包含示例,并反映出利用网络获取帮助的过程)
    软件工程学习总结
    南通大学教务管理微信公众号体验
    设计一款给爸爸妈妈用的手机
    第二次作业
    web browser 发展史
    c++用法的学习心得
    电梯调度
    一个数组既有正数也有负数,计算出它的子数组和的最大值。
  • 原文地址:https://www.cnblogs.com/chelinger/p/11586744.html
Copyright © 2011-2022 走看看