链接:
https://www.nowcoder.com/acm/contest/105/G
来源:牛客网
来源:牛客网
又见斐波那契
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
空间限制: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
2
3
100
输出
1
16
57
558616258
16
57
558616258
解题思路:如果你不会矩阵快速幂,那么这题估计就凉了,在这道题中,当n>2时的项是一个矩阵乘以前一项的值,当n=2时,f[2] = f[1] + f[0] + 8 + 4 + 2 + 1。这时f[2]成了一个首项,而后面的每一项的计算方式为
![](https://i-blog.csdnimg.cn/blog_migrate/756fc25ffc71e8b74ad58067aa528b09.png)
如图就是我们构造出的矩阵了,所谓的矩阵快速幂其实就是求一个矩阵的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;
}