关于斐波那契数列的复杂度最低算法

Description

  zyf总是有很多奇异的想法,他最近常常幻想着以后能开这么一个工厂,可以把前三天里生产出来的东西拿到今天来拼在一起作为今天生产的东西。假如前三天生产出来的产品数分别是x,y,z,那么今天就能生产出x+y+z个。这样一来只要前三天的投入,接下来的工厂每一天都是0成本运作,但产品数却在极速增加,相当暴利。
  当然,为了防止地球被破坏,为了维护世界的和平,zyf是不会让工厂每天生产出来的东西超过1000000006个的,如果超过了,就不停减去1000000007,减到不超过为止。
  现在zyf想知道如果第一、二、三天分别生产a,b,c个产品的话,第n天会生产出多少产品呢?

Input
输入数据的第一行case数。
接下来每一行都有四个数字a,b,c,n(1<=a,b,c,n<=10^9),意义如上文.
Output
对于每个case输出一行,第n天生产的产品数。
Sample Input
2
1 2 3 4
1 1 1 5
Sample Output
6
5

#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#define div 1000000007
/*
A=
0 0 1

1 0 1

0 1 1
*/
// (a[n],a[n+1],a[n+2])*A=(a[n+1],a[n+2],a[n+3])
//然后求A的n 次方
void multiply(long long  a[][4],long long   b[][4])          //两个矩阵相乘
{
    long long  c[4][4]={0};
    int i ,j,k;
    for(i=0;i<3;i++)
        for(j=0;j<3;j++)
            for(k=0;k<3;k++)
                c[i][j]+=(a[i][k]%div)*(b[k][j]%div);
    for(i=0;i<3;i++)
         for(j=0;j<3;j++)
              a[i][j]=c[i][j]%div;
}

void  power(long long  a[][4],int n)                        //一个矩阵的n次方
{
    int i ,j;
    long long  b[4][4];
    memcpy(b,a,sizeof(b));
    if(n>1)
    {
         if(n%2)                                //n为奇数,a^n=a^(n-1)/2*a^(n-1)/2*a;
         {
             power(a,(n-1)/2);
             multiply(a,a);
             multiply(a,b);
         }
        else                                      //n为偶数 a^n=a^(n-1)/2*a^(n-1)/2
        {
            power(a,n/2);
            multiply(a,a);
        }
    }
}

int main()
{
   int a[4]={0};
   int n;
   long long ans;
   int i ,j;
   int p=0,t;
   long long  matrix1[4][4]={{0,0,1},{1,0,1},{0,1,1}};
   long long   matrix[4][4]={0};
   scanf("%d",&t);
   while(p++!=t)
   {
      ans=0;
      memcpy(matrix,matrix1,sizeof(matrix1));
     for(i=0;i<3;i++)
     {
        scanf("%d",&a[i]);
     }
     scanf("%d",&n);
     if(n<4)                                //n<4则直接输出前三个的 一个
     {
        ans=a[n-1];
     }
     else
     {
        power(matrix,n-3);         //求出矩阵的n 次方
        for(i=0;i<3;i++)
            ans+=matrix[i][2]*a[i]%div;
     }
    printf("%lld\n",ans%div);
  }
  return 0;
}
我这个写的是3个的,2个的更简单点的



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值