更加洛谷的观感感受
写数论文章写爽了。
矩阵快速幂
矩阵乘法
矩阵乘法要求
设 A 为 m×p 的矩阵,B 为 p×n 的矩阵。
矩阵乘法必须第一个矩阵的列数等于第二个矩阵的行数。
A×B 是一个 m×n 的矩阵。
矩阵乘法定义
设 A×B=C,则 Ci,j 为:
Ci,j=k=1∑pAi,k×Bk,j
矩阵乘法示例
假如:
A=[142536],B=⎣⎢⎡135246⎦⎥⎤
请你计算一下 A×B 的值。
我们一起计算一下:
C1,1C1,2C2,1C2,2=1×1+2×3+3×5=22=1×2+2×4+3×6=28=4×1+5×3+6×5=49=4×2+5×4+6×6=64
即:
C=[22492864]
矩阵的幂运算
计算 C=[1221]3:
- 先算二次幂:
[1221]2=[1221]×[1221]=[5445]
- 再算三次幂:
[5445]×[1221]=[13141413]
单位矩阵
单位矩阵 I=[1001],与任意矩阵相乘不改变其值。
一个 n×n 的单位矩阵为主对角线为 1,其他为 0 的矩阵。
矩阵快速幂的实现
比较简单,建立一个矩阵结构体封装即可。
class matrix{
public:
matrix()
:n(0)
{
memset(c, 0, sizeof(c));
}
int* operator[](int t)
{
return c[t];
}
void init()
{
for(int i = 1; i <= n; i++)
c[i][i] = 1;
}
int size()
{
return n;
}
private:
int c[110][110];
int n;
};
matrix operator*(matrix x, matrix y)
{
matrix ans;
int n = x.size();
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
for(int k = 1; k <= n; k++)
ans[i][j] += x[i][k] * y[k][j];
}
matrix quick_pow(matrix x, int y)
{
matrix ans;
ans.init();
while(y)
{
if(y & 1) ans = ans * x;
y >>= 1;
x = x * x;
}
return ans;
}
时间复杂度为:O(n3×logn),其中 y 为指数, n 为矩阵长度。
矩阵加速递推
求斐波那契数列(P1962 斐波那契数列):
Fn={1Fn−1+Fn−2(n≤2)(n>2)
1≤n≤263
思路
构造矩阵
我们把斐波那契数列的相邻两项表示为一个矩阵 [FnFn−1],我们希望通过 [Fn−1Fn−2] 推出 [FnFn−1]。
构造转移矩阵
我们构造一个矩阵 A,使得:
[Fn−1Fn−2]×A=[FnFn−1]
根据递推关系:
{Fn=Fn−1×1+Fn−2×1Fn−1=Fn−1×1+Fn−2×0
观察可得:
A=[1110]
递推
我们发现:
[F2F1]×An−2=[FnFn−1]
时间复杂度
矩阵快速幂为 O(n3logy),而矩阵的长度为 2,y 为题目中的 n−2,所以时间复杂度为 O(8logn),就是 O(logn)。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e9 + 7;
int n = 2;
struct matrix{
int c[3][3];
matrix()
{
memset(c, 0, sizeof(c));
}
void init()
{
for(int i = 1; i <= n; i++)
c[i][i] = 1;
}
};
matrix operator*(matrix x, matrix y)
{
matrix ans;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
for(int k = 1; k <= n; k++)
ans.c[i][j] = (ans.c[i][j] + x.c[i][k] * y.c[k][j]) % mod;
return ans;
}
matrix quick_pow(matrix x, int y)
{
matrix ans;
ans.init();
while(y)
{
if(y & 1) ans = ans * x;
y >>= 1;
x = x * x;
}
return ans;
}
signed main()
{
int m;
cin >> m;
if(m <= 2) cout << 1, exit(0);
matrix a;
a.c[1][1] = a.c[1][2] = 1;
matrix b;
b.c[1][1] = b.c[1][2] = b.c[2][1] = 1;
b = quick_pow(b, m - 2);
matrix ans = a * b;
cout << ans.c[1][1];
return 0;
}
作业
已知一个函数为:
f(n)={1f(n−1)×f(n−2)×f(n−3)(n≤3)(n>3)
给出 n(1≤n≤1018) 求出 f(n)mod114514。