hdu3117 Fibonacci Numbers (矩阵快速幂)

题目大意:输入一个n,求n的斐波那契数值的前四位和后四位,如果位数小于等于8 位,则全部输出。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3117点击打开链接


解题思路:后四位可用矩阵快速幂求出,而前四位则可用公式求出,借鉴了某大神的博客http://blog.sina.com.cn/s/blog_9bf748f301019q3t.html

求解前四位的方法:斐波那契数列的通项公式如下:a_n= \frac{1}{\sqrt{5}}\left [ {\left ( {\frac{1+\sqrt{5}}{2}} \right )^n-{}\left ( {\frac{1-\sqrt{5}}{2}} \right )^n} \right ], 改变通项的形式:

F(n)=(1/√5)*[((1+√5)/2)^n-((1-√5)/2)^n]=(1/√5)*[((1+√5)/2)^n*(1-((1-√5)/(1+√5))^n)]

即F(n)的各项可以由以上通项公式求得,而不是采用迭代。

对变化后的通项取对数,则得下式:

log10(F(n))=-0.5*log10(5.0)+((double)n)*log(f)/log(10.0)+log10(1-((1-√5)/(1+√5))^n)

其中第三部分非常小,当n很大时趋近于0,可以忽略掉。

因此,采用下式即可:

temp=-0.5*log(5.0)/log(10.0)+((double)n)*log(s)/log(10.0); 

求解后四位的方法:矩阵快速幂

斐波那契数列的矩阵表示形式为:

代码如下:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define N 2
int  M, n;
typedef struct
{
     int m[2][2];
}Matrax;

Matrax multi(Matrax a, Matrax b)
{
     Matrax c;
     for(int i = 0; i < N; i ++)
             for(int j = 0; j < N; j ++)
             {
                      c.m[i][j] = 0;
                      for(int k = 0; k < N; k ++)
                      {
                              c.m[i][j] = c.m[i][j] + a.m[i][k] * b.m[k][j] % M;
                      }
                      c.m[i][j] %= M;
            }
     return  c;
}

int  power(Matrax& p)
{
     if(n<=1) return n;
     Matrax ans;
     ans.m[0][0] = 1;ans.m[0][1] = 0;
     ans.m[1][0] = 0;ans.m[1][1] = 1;
    /* n --;
     while(n)
     {
          if(n % 2)
          {
              ans = multi(ans, p);

          }
          n /= 2;
          p = multi(p, p);

     }*/
     n --;
     while(n)
     {
          if(n & 1)
          {
              ans = multi(ans, p);
              n--;
          }
          else{
              n= n/2;
              p= multi(p , p);
          }
     }
     return ans.m[0][0] % M;
}

int  main()
{
     Matrax p;
     while(~scanf("%d", &n))
     {
            M = 1e4;
            p.m[0][0] = 1; p.m[0][1] = 1;
            p.m[1][0] = 1; p.m[1][1] = 0;
            if(n <= 39)
            {
                   M = 1e9;
                   printf("%d\n",power(p));
            }
            else
            {
                   double temp;
                   double s = (sqrt(5.0) + 1.0) / 2.0;
                   temp = -0.5 * log(5.0) / log(10.0) + ((double)n) * log(s)/log(10.0);
                   temp = temp -floor(temp);
                   temp = pow(10.0, temp);
                   while(temp < 1000) temp = temp * 10;
                   printf("%04d...%04d\n", (int)temp, power(p));
            }
     }
     return 0;
}

输出的时候需要注意一下,用%04d ,而不能用%4d,%04d在位数不足四位的情况下,前面自动补零,而%4d就只是右对齐。

P.S.  hdu3117要是过掉了的话, hdu1568 那就轻松加愉快啦啦啦~~~




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值