2018年湘潭大学程序设计竞赛(重现赛) G-又见斐波那契 (矩阵快速幂)

链接: https://www.nowcoder.com/acm/contest/105/G
来源:牛客网
又见斐波那契


时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
 64bit IO Format: %lld

题目描述


这是一个加强版的斐波那契数列。   给定递推式     求F(n)的值,由于这个值可能太大,请对109+7取模。
输入描述:
第一行是一个整数T(1 ≤ T ≤ 1000),表示样例的个数。以后每个样例一行,是一个整数n(1 ≤ n ≤ 1018)。
输出描述:
每个样例输出一行,一个整数,表示F(n) mod 1000000007。

示例1

输入
4
1
2
3
100

输出
1
16
57
558616258

解题思路:如果你不会矩阵快速幂,那么这题估计就凉了,在这道题中,当n>2时的项是一个矩阵乘以前一项的值,当n=2时,f[2] = f[1] + f[0] + 8 + 4 + 2 + 1。这时f[2]成了一个首项,而后面的每一项的计算方式为
如图就是我们构造出的矩阵了,所谓的矩阵快速幂其实就是求一个矩阵的n次方,就类似于普通的快速幂一样,就是多了一个矩阵的计算而已。

AC代码:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<queue>
#include<map>
#define bug printf("--------");
using namespace std;
typedef long long LL;
const int INF = 1e9;
const int mod = 1e9+7;

int n, ans, vis[20][20], a[20][20], s[20];

//矩阵快速幂关键是构造出所需要的矩阵
struct node
{
    LL a[6][6] =  {{1, 1, 1, 1, 1, 1},
                   {1, 0, 0, 0, 0, 0},
                   {0, 0, 1, 3, 3, 1},
                   {0, 0, 0, 1, 2, 1},
                   {0, 0, 0, 0, 1, 1},
                   {0, 0, 0, 0, 0, 1},
                   };
};

node cacu(node u, node v, int x, int y, int z) //求两个矩阵的乘积
{
    node qu;
    for(int i = 0; i < x; i ++) {
        for(int k = 0; k < y; k ++) {
            qu.a[i][k] = 0; //记得这里初始化
            for(int j = 0; j < z; j ++) {
                qu.a[i][k] += (u.a[i][j]*v.a[j][k])%mod;
            }
            qu.a[i][k] %= mod;
        }
    }
    return qu;
}

node power(LL n) //快速幂
{
    node a, b; //其他的写法可能要把b初始化为单位矩阵
    while(n > 0) {
        if(n&1) {
            b = cacu(a, b, 6, 6, 6);
        }
        a = cacu(a, a, 6, 6, 6);
        n /= 2;
    }
    return b;
}

node in(node x) //首项矩阵F[2]
{
    x.a[0][0] = 1;
    x.a[1][0] = 0;
    x.a[2][0] = 8;
    x.a[3][0] = 4;
    x.a[4][0] = 2;
    x.a[5][0] = 1;
    return x;
}

int main()
{
    LL T, n;
    scanf("%lld", &T);
    while(T --) {
        scanf("%lldd", &n);
        node ans, p;
        ans = in(ans);
        if(n <= 1) {
            printf("%lld\n", n);
            continue;
        }
        p = power(n-2);
        ans = cacu(p, ans, 6, 1, 6);
        printf("%lld\n", ans.a[0][0]); //输出F[n]即可
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值