P1939 【模板】矩阵加速(数列)
题目描述
a[1]=a[2]=a[3]=1
a[x]=a[x-3]+a[x-1] (x>3)
求a数列的第n项对1000000007(10^9+7)取余的值。
输入输出格式
输入格式:
第一行一个整数T,表示询问个数。
以下T行,每行一个正整数n。
输出格式:
每行输出一个非负整数表示答案。
输入输出样例
输入样例#1:
3
6
8
10
输出样例#1:
4
9
19
此题乍一看可以用离散数学里学过的递推公式求解, 但是x**3 - x**2 - 1 = 0个特征方程似乎是有虚数解, 那么看来是不行的.
再回顾之前学过的矩阵快速幂求斐波那契数列,这个数列和斐波那契非常相似,都是递推,那么是否可以用同样的方法用矩阵去做呢?
结合题的名字”【模板】矩阵加速(数列)”, 标程应该就是这样了吧.
OK, 经过推导构造出了矩阵[[1, 0, 1], [1, 0, 0], [0, 1, 0]].
思路和斐波那契数列的矩阵快速幂是一样的.
找出关系矩阵 -> 矩阵计算 + 快速幂
#include <iostream>
#include <cstring>
using namespace std;
typedef long long LL;
const LL mode = 1000000007;
void calc(LL ans[3][3], LL matrix[3][3])
{
LL tmp[3][3];
memset(tmp, 0, sizeof(tmp));
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
for (int k = 0; k < 3; ++k) {
tmp[i][j] += ans[i][k] * matrix[k][j];
tmp[i][j] %= mode;
}
}
}
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
ans[i][j] = tmp[i][j];
}
}
}
int main()
{
LL T, n;
cin >> T;
for (int i = 0; i < T; ++i) {
LL matrix[3][3] = {{1, 0, 1}, {1, 0, 0}, {0, 1, 0}};
LL ans[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
cin >> n;
if (n <= 3) {
cout << 1 << endl;
continue;
}
n -= 3;
while (n) {
if (n & 1) {
calc(ans, matrix);
}
calc(matrix, matrix);
n /= 2;
}
cout << (ans[0][0] + ans[0][1] + ans[0][2]) % mode << endl;
}
}