数列满足
G1=2
G2=3
Gi=Gi−1×Gi−2 (i>2)
求该数列 G 的前 n 项的乘积对 998244353 取模的结果。
很显然 gi 的质因子只有 2 和 3,设 gi=2pi⋅3qi,问题转化为求 p,q。
由于 gi=gi−1⋅gi−2,所以 pi,qi 只能从 pi−1,qi−1 和 pi−2,qi−2 继承而来。
因为是相乘的关系,所以指数相加,也就是 pi=pi−1+pi−2,qi=qi−1+qi−2。
i=3:p=1,q=1
i=4:p=1,q=2
i=5:p=2,1=3.......
很明显满足p:i=3时开始的斐波那契,q满足i=2时开始的
然后斐波那契前n项的和又满足。。。。一个斐波那契
1 1 2 3 5 8
和:初始1 1+1=2 2+1=3 3+2=5 8。。。
所以sp=i从2开始的斐波那契,sq=i从1开始的斐波那契
知识点:快速幂
#include <iostream>
using namespace std;
const int MOD = 998244353;
// 快速幂
long long qpow(long long a, long long b) {
long long res = 1;
a %= MOD;
while (b) {
if (b & 1) res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
int main() {
long long n;
cin >> n;
if (n == 1) {
cout << 2 << endl; // 只有 G1 = 2
return 0;
}
if (n == 2) {
cout << 6 << endl; // 2 * 3 = 6
return 0;
}
// 计算斐波那契数列模 MOD-1
// 我们需要 Fib(n) 和 Fib(n+1) 模 MOD-1
const int PHI = MOD - 1; // 欧拉定理指数取模用
// 初始化斐波那契
long long f1 = 1, f2 = 1, fn = 1; // Fib(1)=1, Fib(2)=1
// 计算 Fib(n) 模 PHI
if (n == 1) {
fn = 1;
} else if (n == 2) {
fn = 1;
} else {
for (int i = 3; i <= n; i++) {
fn = (f1 + f2) % PHI;
f1 = f2;
f2 = fn;
}
}
long long Sp = fn; // Sp(n) = Fib(n)
// 重置计算 Fib(n+1)
f1 = 1, f2 = 1;
if (n + 1 == 1) {
fn = 1;
} else if (n + 1 == 2) {
fn = 1;
} else {
for (int i = 3; i <= n + 1; i++) {
fn = (f1 + f2) % PHI;
f1 = f2;
f2 = fn;
}
}
long long Sq = (fn - 1 + PHI) % PHI; // Sq(n) = Fib(n+1) - 1
// 最终结果 = 2^Sp * 3^Sq mod MOD
long long ans = qpow(2, Sp) * qpow(3, Sq) % MOD;
cout << ans << endl;
return 0;
}
此时我们如果注意到有条件n<10^18,那么直接求斐波那契就超时了,应该用矩阵快速幂
一、基本概念
1.1 快速幂
快速幂是一种快速计算 ab的算法,时间复杂度 O(log b):
long long qpow(long long a, long long b) {
long long res = 1;
while (b) {
if (b & 1) res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
1.2 矩阵快速幂
矩阵快速幂是将快速幂的思想应用到矩阵乘法上,用于快速计算矩阵的 n 次幂:
-
普通矩阵乘法:O(k³) 时间(k×k矩阵)
-
矩阵快速幂:O(k³ log n) 时间计算 Mn
二、斐波那契数列的矩阵表示
2.1 递推式
斐波那契数列:F1=1,F2=1,Fn=Fn−1+Fn−2
2.2 矩阵形式
我们可以写成:
三、矩阵快速幂的实现
3.1 矩阵结构
const int MOD = 998244353;
struct Matrix {
long long m[2][2];
Matrix() {
m[0][0] = m[1][1] = 1; // 单位矩阵
m[0][1] = m[1][0] = 0;
}
Matrix(long long a, long long b, long long c, long long d) {
m[0][0] = a; m[0][1] = b;
m[1][0] = c; m[1][1] = d;
}
};
3.2 矩阵乘法
Matrix multiply(const Matrix& A, const Matrix& B) {
Matrix C;
C.m[0][0] = (A.m[0][0]*B.m[0][0] + A.m[0][1]*B.m[1][0]) % MOD;
C.m[0][1] = (A.m[0][0]*B.m[0][1] + A.m[0][1]*B.m[1][1]) % MOD;
C.m[1][0] = (A.m[1][0]*B.m[0][0] + A.m[1][1]*B.m[1][0]) % MOD;
C.m[1][1] = (A.m[1][0]*B.m[0][1] + A.m[1][1]*B.m[1][1]) % MOD;
return C;
}
3.3 矩阵快速幂
Matrix mat_pow(Matrix base, long long n) {
Matrix result; // 初始为单位矩阵
while (n > 0) {
if (n & 1) {
result = multiply(result, base);
}
base = multiply(base, base);
n >>= 1;
}
return result;
}
四、计算斐波那契数列
4.1 完整实现
long long fib(long long n) {
if (n <= 0) return 0;
if (n == 1 || n == 2) return 1;
Matrix base(1, 1, 1, 0); // 转移矩阵
Matrix res = mat_pow(base, n - 2); // 计算 M^{n-2}
// F_n = res.m[0][0]*F_2 + res.m[0][1]*F_1
return (res.m[0][0] + res.m[0][1]) % MOD;
}
#include <iostream>
using namespace std;
const int MOD = 998244353;
// 矩阵快速幂计算斐波那契数列的第 n 项
long long fib(long long n) {
if (n <= 0) return 0;
if (n == 1 || n == 2) return 1;
n -= 2; // 从第三项开始
long long a = 1, b = 1, c, d;
long long aa = 1, bb = 1, cc, dd;
// 矩阵快速幂:初始矩阵为 {{1,1},{1,0}} 的 n 次幂
long long res[2][2] = {{1,0},{0,1}}; // 单位矩阵
long long base[2][2] = {{1,1},{1,0}};
while (n > 0) {
if (n & 1) {
// res = res * base
long long t00 = (res[0][0]*base[0][0] + res[0][1]*base[1][0]) % (MOD-1);
long long t01 = (res[0][0]*base[0][1] + res[0][1]*base[1][1]) % (MOD-1);
long long t10 = (res[1][0]*base[0][0] + res[1][1]*base[1][0]) % (MOD-1);
long long t11 = (res[1][0]*base[0][1] + res[1][1]*base[1][1]) % (MOD-1);
res[0][0]=t00; res[0][1]=t01; res[1][0]=t10; res[1][1]=t11;
}
// base = base * base
long long t00 = (base[0][0]*base[0][0] + base[0][1]*base[1][0]) % (MOD-1);
long long t01 = (base[0][0]*base[0][1] + base[0][1]*base[1][1]) % (MOD-1);
long long t10 = (base[1][0]*base[0][0] + base[1][1]*base[1][0]) % (MOD-1);
long long t11 = (base[1][0]*base[0][1] + base[1][1]*base[1][1]) % (MOD-1);
base[0][0]=t00; base[0][1]=t01; base[1][0]=t10; base[1][1]=t11;
n >>= 1;
}
// 初始 F1=1, F2=1, 乘以矩阵 {{F2,F1},{F1,F0}} 得到 F_{n+2}
// 我们只需要 F_{n+2} 中的一项即可
return (res[0][0] + res[0][1]) % (MOD-1);
}
// 快速幂
long long qpow(long long a, long long b) {
long long res = 1;
a %= MOD;
while (b) {
if (b & 1) res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
int main() {
long long n;
cin >> n;
if (n == 1) {
// 只有 G1 = 2
cout << 2 << endl;
return 0;
}
if (n == 2) {
// G1 * G2 = 2 * 3 = 6
cout << 6 << endl;
return 0;
}
long long Sp = fib(n); // fib 函数返回的是模 MOD-1 的结果
// 计算 Fib(n+1) mod (MOD-1)
long long Sq = fib(n+1);
Sq = (Sq - 1 + (MOD-1)) % (MOD-1);
// 最终结果 = 2^Sp * 3^Sq mod MOD
long long ans = qpow(2, Sp) * qpow(3, Sq) % MOD;
cout << ans << endl;
return 0;
}