牛客网 又见斐波那契 矩阵快速幂

题目链接

链接:https://ac.nowcoder.com/acm/contest/105/G
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
这是一个加强版的斐波那契数列。
给定递推式
在这里插入图片描述
求F(n)的值,由于这个值可能太大,请对10^9+7取模。
输入描述:
第一行是一个整数T(1 ≤ T ≤ 1000),表示样例的个数。
以后每个样例一行,是一个整数n(1 ≤ n ≤ 10^18)。
输出描述:
每个样例输出一行,一个整数,表示F(n) mod 1000000007。
示例1
输入
4
1
2
3
100
输出
1
16
57
558616258

解题思路:
这个公式相比普通的斐波那契数列多了后面四项,看一眼数据范围,肯定不能使用普通的 o(n) 算法了,因此这里需要使用矩阵快速幂(斐波那契数列的项数n一旦过大,就要考虑快速幂,普通算法时间、空间开销都太大)

对于给定的递推式:在这里插入图片描述
我们可以得到如下矩阵形式:
[ F i F i − 1 ( i + 1 ) 3 ( i + 1 ) 2 i + 1 1 ] = [ 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 ] [ F i − 1 F i − 2 i 3 i 2 i 1 ] \left[ \begin{matrix} F_i\\ F_{i-1} \\ (i+1)^3\\ (i+1)^2 \\ i+1\\ 1 \end{matrix} \right]= \left[ \begin{matrix} 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 \end{matrix} \right] \left[ \begin{matrix} F_{i-1}\\ F_{i-2} \\ i^3\\ i^2 \\ i\\ 1 \end{matrix} \right] FiFi1(i+1)3(i+1)2i+11=110000100000101000103100103210101111Fi1Fi2i3i2i1

又有F(0)=0,F(1)=1,可得
[ F i F i − 1 ( i + 1 ) 3 ( i + 1 ) 2 i + 1 1 ] = [ 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 ] i − 1 [ F 1 F 0 2 3 2 2 2 1 ] = [ 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 ] i − 1 [ 1 0 8 4 2 1 ] \left[ \begin{matrix} F_i\\ F_{i-1} \\ (i+1)^3\\ (i+1)^2 \\ i+1\\ 1 \end{matrix} \right] = \left[ \begin{matrix} 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 \end{matrix} \right]^{i-1} \left[ \begin{matrix} F_{1}\\ F_{0} \\ 2^3\\ 2^2 \\ 2\\ 1 \end{matrix} \right] = \left[ \begin{matrix} 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 \end{matrix} \right]^{i-1} \left[ \begin{matrix} 1\\ 0\\ 8\\ 4 \\ 2\\ 1 \end{matrix} \right] FiFi1(i+1)3(i+1)2i+11=110000100000101000103100103210101111i1F1F0232221=110000100000101000103100103210101111i1108421

AC代码:

#include<iostream>
#include<stdio.h>
#include<vector>
using namespace std;
typedef long long ll;
// 用二维vector来表示矩阵
//注意使用ll类型  
typedef vector<ll> vec;
typedef vector<vec> mat;
const int M = 1e9 + 7;
mat mul(mat a, mat b) {
	mat c(a.size(), vec(b[0].size()));
	for (int i = 0; i < a.size(); i++) {
		for (int k = 0; k < b.size(); k++) {
			for (int j = 0; j < b[0].size(); j++) {
				c[i][j] = (c[i][j] + a[i][k] * b[k][j]) % M;
			}
		}
	}
	return c;
}
mat mod_pow(mat a, ll n) {
	mat b(a.size(), vec(a.size()));
	for (int i = 0; i < a.size(); i++) {
		b[i][i] = 1;
	}
	while (n > 0) {
		if (n & 1) b = mul(b, a);
		a = mul(a, a);
		n >>= 1;
	}
	return b;
}
int main() {
	int t; ll n;
	scanf("%d", &t);
	while (t--) {
		scanf("%lld", &n);
		if (n == 1) {
			printf("%d\n", 1);
			continue;
		}
		mat a(6, vec(6));//当然这一步已经包含了初始化为0 下面赋值的时候只将不为0的项重新赋值也可以
		a[0][0] = 1; a[0][1] = 1; a[0][2] = 1; a[0][3] = 1; a[0][4] = 1; a[0][5] = 1;
		a[1][0] = 1; a[1][1] = 0; a[1][2] = 0; a[1][3] = 0; a[1][4] = 0; a[1][5] = 0;
		a[2][0] = 0; a[2][1] = 0; a[2][2] = 1; a[2][3] = 3; a[2][4] = 3; a[2][5] = 1;
		a[3][0] = 0; a[3][1] = 0; a[3][2] = 0; a[3][3] = 1; a[3][4] = 2; a[3][5] = 1;
		a[4][0] = 0; a[4][1] = 0; a[4][2] = 0; a[4][3] = 0; a[4][4] = 1; a[4][5] = 1;
		a[5][0] = 0; a[5][1] = 0; a[5][2] = 0; a[5][3] = 0; a[5][4] = 0; a[5][5] = 1;
		a = mod_pow(a, n - 1);
		ll ans;
		ans = (a[0][0] + 8*a[0][2] + 4*a[0][3] + 2*a[0][4] + a[0][5]) % M;
		printf("%lld\n", ans);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值