poj3070斐波那契数列求解


问题

先看下面的问题: [ poj-3070]

Description
In the Fibonacci integer sequence, F0 = 0, F1 = 1, and Fn = Fn − 1 + Fn − 2 for n ≥ 2. For example, the first ten terms of the Fibonacci sequence are:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, …
Given an integer n, your goal is to compute the last 4 digits of Fn.
Input
The input test file will contain multiple test cases. Each test case consists of a single line containing n (where 0 ≤ n ≤ 1,000,000,000). The end-of-file is denoted by a single line containing the number −1.
Output
For each test case, print the last four digits of Fn. If the last four digits of Fn are all zeros, print ‘0’; otherwise, omit any leading zeros (i.e., print Fn mod 10000).
Sample Input
0
9
999999999
1000000000
-1
Sample Output
0
34
626
6875

思路

之前讲过的矩阵快速幂求模求解即可。只不过本题在题目描述的过程中给出了另外一种矩阵表示。见下面证明:

[F2F1F1F0]=[1110](1)

由于(1)恒成立,所以当 n>=1时,等式两边同乘右边的常数矩阵,有:
[Fn+1FnFnFn1]=[1110]n(2)

本质是求解如下矩阵:
[1110]n(3)

从而将斐波那契数列问题转化为矩阵乘法的问题,又可以进一步转化为矩阵快速幂。根之前的区别只是最终求解矩阵的区别。

代码


#include <iostream>
#include <cstring>
#include <fstream>
//#define LOCAL
const int maxn = 8;
const int MOD = 10000;

struct Matrix{
        int mat_[maxn][maxn];
        int size_;

        Matrix( int s = 0 ) : size_( s )
        {
                std::memset( mat_, 0, sizeof(mat_) );
        }
        Matrix( const Matrix& rhs )
        {
                size_ = rhs.size_;
                *this = rhs;
        }
        int init()
        {
                mat_[0][0] = 1;
                mat_[0][1] = 1;
                mat_[1][0] = 1;
                mat_[1][1] = 0;

                return 0;
        }
        int set_diag( int val )
        {
                for( int i = 0; i < size_; ++i )
                {
                        for( int j = 0; j < size_; ++j )
                                mat_[i][j] = (i==j)?val:0;
                }

                return 0;
        }
        Matrix& operator=( const Matrix& rhs )
        {
                for( int i = 0; i < size_; ++i )
                {
                        for( int j = 0; j < size_; ++j )
                                mat_[i][j] = rhs.mat_[i][j];
                }
                return *this;
        }
        Matrix operator*( const Matrix& rhs )
        {
                Matrix ret(2);
                for( int i = 0; i < size_; ++i )
                {
                        for( int j = 0; j < size_; ++j )
                        {
                                for( int index = 0; index < size_; ++index )
                                {
                                        ret.mat_[i][j] = (ret.mat_[i][j] +  (mat_[i][index]%MOD * rhs.mat_[index][j]%MOD)%MOD)%MOD;
                                }
                        }
                }
                return ret;
        }
        Matrix& operator^( int b )
        {
                Matrix a(*this);
                Matrix ans(2);
                ans.set_diag(1);
                while(b)
                {
                        if(b%2)
                                ans = ans * a;
                        a = a*a;
                        b /= 2;
                }
                *this = ans;
                return *this;
        }
};

int main( void )
{
#ifdef LOCAL
        std::ifstream cin("input.dat");
#endif
        int n = 0;
        while( std::cin >> n, n != -1 )
        {
                if(!n)
                        std::cout << 0 << std::endl;
                else
                {
                        Matrix a(2);
                        a.init();
                        a^n;
                        std::cout << a.mat_[0][1] << std::endl;
                }
        }
#ifdef LOCAL
        cin.close();
#endif
        return 0;
}

总结

一遍过,没有遇见太大问题。感受到了引入矩阵后对于问题的简化。矩阵真是个好东西。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值