1 条题解
-
0
思路与算法
补充 ,使用列向量 。递推可写作
$$V_{i+1}=Q V_i,\quad Q=\begin{pmatrix}1&1\\1&0\end{pmatrix}.$$初始向量 ,所以 。用二进制快速幂计算矩阵幂,结果从单位矩阵开始,指数为1的二进制位将当前矩阵乘入结果,每轮把底矩阵平方、指数右移。最后取向量第一项并模 。本题每次输入同时给 ,与固定模数版本协议不同。
正确性说明
转移第一行给出 ,第二行复制 ,故一次矩阵乘法正确地把状态推进一项。由初始向量归纳,连续推进 次得到 。快速幂循环保持“结果矩阵乘当前底矩阵的剩余指数次幂”等于目标幂,拆出奇数位并平方不会改变该值;指数归零时结果即目标矩阵。整数模运算保持加乘同余,故输出为所求余数。
复杂度
设状态维度为 (本题为固定常数)。初始化转移矩阵和单位矩阵耗时 ;一次矩阵乘法 ,二进制幂进行 轮,最后矩阵乘初始向量 。含初始化总时间 ,固定维度可简为 。矩阵和向量额外空间 ,不按 分配数组。
易错点
- 初始位置是1,幂为 ; 时用零次幂单位矩阵。
- 模数可以为1,单位矩阵对角元也按 初始化,结果为0。
- 使用列向量,矩阵与向量的乘法方向一致。输入的 必须参与每次模运算。
- 全部乘法采用64位,模数至 ,模内乘积及即时约简的累加均安全。
- 最大 不可逐项递推;独立答案用倍增公式,并以800个小范围逐项递推用例交叉验证。
参考代码(C++11)
#include <bits/stdc++.h> using namespace std; using ll = long long; const int D = 2; ll mod; struct Matrix { ll a[D][D]{}; }; Matrix multiply(const Matrix &x, const Matrix &y) { Matrix out; for (int i = 0; i < D; i++) for (int j = 0; j < D; j++) for (int k = 0; k < D; k++) out.a[i][j] = (out.a[i][j] + x.a[i][k] * y.a[k][j]) % mod; return out; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); ll n; cin >> n >> mod; ll raw[D][D] = {{1, 1}, {1, 0}}; Matrix base, result; for (int i = 0; i < D; i++) { result.a[i][i] = 1 % mod; for (int j = 0; j < D; j++) base.a[i][j] = raw[i][j] % mod; } ll power = n - 1; while (power) { if (power & 1) result = multiply(result, base); base = multiply(base, base); power >>= 1; } ll initial[D] = {1, 0}, answer = 0; for (int j = 0; j < D; j++) answer = (answer + result.a[0][j] * initial[j]) % mod; cout << answer << '\n'; }
- 1