题目链接
题目描述
定义数列 满足:
给定 ,请求出
的值。由于结果可能很大,请对
取模。
解题思路
这是一个典型的线性递推关系求解问题。由于 的范围可以达到
,使用简单的
递推或递归会超时。对于这类问题,标准的高效解法是矩阵快速幂 (Matrix Exponentiation)。
算法步骤
-
建立状态向量: 递推关系
依赖于前三项中的两项。为了能够从第
步的状态推导出第
步的状态,我们需要维护一个包含足够历史信息的状态向量。选择一个
的向量是合适的,因为它包含了计算
所需的所有项:
-
构建转移矩阵: 我们的目标是找到一个
的转移矩阵
,使得:
根据递推关系填充矩阵
:
- 第一行(计算
):
。所以第一行为
。
- 第二行(计算
):
。所以第二行为
。
- 第三行(计算
):
。所以第三行为
。
因此,转移矩阵
为:
- 第一行(计算
-
应用矩阵快速幂: 通过重复应用上述关系,我们可以从一个已知的初始状态(例如
时的状态)推广到任意的
:
这个公式对于
成立。根据题意,
,所以我们的初始状态向量为
。
-
求解:
- 对于给定的
,如果
,答案直接为 1。
- 如果
,我们使用矩阵快速幂算法计算出
,记为
。
- 最终的
是
与初始向量相乘后得到的向量的第一个元素。即:
由于
,这简化为:
- 对于给定的
这样,我们就将问题转化为了一个 矩阵的快速幂计算,可以在
的时间内解决单次查询。
代码
#include <iostream>
#include <vector>
using namespace std;
const int MOD = 1e9 + 7;
// 定义矩阵类型
using Matrix = vector<vector<long long>>;
// 矩阵乘法 (3x3)
Matrix multiply(const Matrix& a, const Matrix& b) {
Matrix c(3, vector<long long>(3, 0));
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
for (int k = 0; k < 3; ++k) {
long long product = a[i][k] * b[k][j];
c[i][j] = (c[i][j] + product % MOD + MOD) % MOD;
}
}
}
return c;
}
// 矩阵快速幂 (3x3)
Matrix matrix_pow(Matrix base, long long exp) {
Matrix res(3, vector<long long>(3, 0));
// 初始化为单位矩阵
for (int i = 0; i < 3; ++i) {
res[i][i] = 1;
}
while (exp > 0) {
if (exp % 2 == 1) {
res = multiply(res, base);
}
base = multiply(base, base);
exp /= 2;
}
return res;
}
void solve() {
long long n;
cin >> n;
if (n <= 3) {
cout << 1 << "\n";
return;
}
Matrix T = {
{1, 0, 1},
{1, 0, 0},
{0, 1, 0}
};
Matrix T_pow = matrix_pow(T, n - 3);
// a_n = T_pow[0][0]*a3 + T_pow[0][1]*a2 + T_pow[0][2]*a1
// since a1=a2=a3=1, a_n is the sum of the first row
long long ans = (T_pow[0][0] + T_pow[0][1] + T_pow[0][2]) % MOD;
cout << ans << "\n";
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
import java.util.Scanner;
public class Main {
static final int MOD = 1_000_000_007;
// 矩阵乘法 (3x3)
public static long[][] multiply(long[][] a, long[][] b) {
long[][] c = new long[3][3];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
for (int k = 0; k < 3; k++) {
long product = a[i][k] * b[k][j];
c[i][j] = (c[i][j] + product % MOD + MOD) % MOD;
}
}
}
return c;
}
// 矩阵快速幂 (3x3)
public static long[][] matrixPow(long[][] base, long exp) {
long[][] res = new long[3][3];
// 初始化为单位矩阵
for (int i = 0; i < 3; i++) {
res[i][i] = 1;
}
while (exp > 0) {
if (exp % 2 == 1) {
res = multiply(res, base);
}
base = multiply(base, base);
exp /= 2;
}
return res;
}
public static void solve(Scanner sc) {
long n = sc.nextLong();
if (n <= 3) {
System.out.println(1);
return;
}
long[][] T = {
{1, 0, 1},
{1, 0, 0},
{0, 1, 0}
};
long[][] T_pow = matrixPow(T, n - 3);
long ans = (T_pow[0][0] + T_pow[0][1] + T_pow[0][2]) % MOD;
System.out.println(ans);
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
while (t-- > 0) {
solve(sc);
}
}
}
import sys
MOD = 10**9 + 7
def multiply(a, b):
c = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
for i in range(3):
for j in range(3):
for k in range(3):
c[i][j] = (c[i][j] + a[i][k] * b[k][j]) % MOD
return c
def matrix_pow(base, exp):
res = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
for i in range(3):
res[i][i] = 1
while exp > 0:
if exp % 2 == 1:
res = multiply(res, base)
base = multiply(base, base)
exp //= 2
return res
def solve():
n = int(sys.stdin.readline())
if n <= 3:
sys.stdout.write("1\n")
return
T = [
[1, 0, 1],
[1, 0, 0],
[0, 1, 0]
]
T_pow = matrix_pow(T, n - 3)
# a_n = T_pow[0][0]*a3 + T_pow[0][1]*a2 + T_pow[0][2]*a1
# since a1=a2=a3=1, a_n is the sum of the first row
ans = (T_pow[0][0] + T_pow[0][1] + T_pow[0][2]) % MOD
sys.stdout.write(str(ans) + '\n')
def main():
try:
t_str = sys.stdin.readline()
if not t_str: return
t = int(t_str)
for _ in range(t):
solve()
except (IOError, ValueError):
return
main()
算法及复杂度
- 算法:矩阵快速幂 (Matrix Exponentiation)
- 时间复杂度:
,其中
是询问次数,
是矩阵维度,
是数列的项数。由于
是一个很小的常数,所以单次查询的复杂度为
。
- 空间复杂度:
,用于存储矩阵。由于
,空间复杂度为
。