矩阵加速递推学习笔记
之前写的太naive了。
因此今日重新写一篇。
前置知识:矩阵乘法
矩阵的一系列操作
直接贴代码吧..
只是一个大概的模板。具体根据题目而定。
class Matrix{
private:
int row,col,s[N][N]; //行,列,元素
public:
Matrix() { //无参数构造函数
row=col=0;
memset(s,0,sizeof(s));
}
Matrix(int n,int m):row(n),col(m){memset(s,0,sizeof(s));} //重载构造函数
void readp() { //输入一个矩阵
for(int i=1;i<=row;i++) {
for(int j=1;j<=col;j++) cin>>s[i][j];
}
}
void printp() { //输出一个矩阵
for(int i=1;i<=row;i++) {
for(int j=1;j<=col;j++) cout<<s[i][j]<<" ";
cout<<endl;
}
}
void transpose() { //矩阵的转置
Matrix y(col,row);
for(int i=1;i<=row;i++) {
for(int j=1;j<=col;j++) y.s[j][i]=s[i][j];
}
*this=y;
}
void identity() { //将该矩阵改成单位矩阵
for(int i=1;i<=row;i++) s[i][i]=1;
}
Matrix operator + (Matrix x) { //重载+
Matrix y(row,col);
for(int i=1;i<=row;i++) {
for(int j=1;j<=col;j++) y.s[i][j]+=s[i][j]+x.s[i][j];
}
return y;
}
Matrix operator * (Matrix x) { //重载*
Matrix y(row,x.col);
for(int i=1;i<=row;i++) {
for(int j=1;j<=x.col;j++) {
for(int k=1;k<=col;k++) {
y.s[i][j]+=s[i][k]*x.s[k][j];
}
}
}
return y;
}
Matrix operator *= (Matrix x) { //重载*=
return *this=*this*x;
}
};
矩阵乘法
重新温故一下矩阵乘法。
举个例子
于是
注意,只有满足
链接
P1962 斐波那契数列
思路
考虑这样一个矩阵
如何变成
呢?
显然
于是若要求
于是便可以矩阵快速幂+矩阵乘法解决。
时间复杂度
代码
#include<bits/stdc++.h>
#define N 5
#define ll long long
#define mod 1000000007
using namespace std;
ll n;
class Matrix{
private:
int row,col;
ll s[N][N];
public:
Matrix() {
row=col=0;
memset(s,0,sizeof(s));
}
Matrix(int _row,int _col):row(_row),col(_col){memset(s,0,sizeof(s));}
Matrix(int n):row(n),col(n){memset(s,0,sizeof(s));}
Matrix operator * (Matrix x) {
Matrix y(row,x.col);
for(int i=1;i<=row;i++) {
for(int j=1;j<=x.col;j++) {
for(int k=1;k<=col;k++) y.s[i][j]=(y.s[i][j]+s[i][k]*x.s[k][j])%mod;
}
}
return y;
}
Matrix operator *= (Matrix x) {
return *this=*this*x;
}
void idenitity() {
for(int i=1;i<=row;i++) s[i][i]=1;
}
void printp() {
cout<<s[1][1]<<endl;
}
void init(int x[][N]) {
for(int i=1;i<=row;i++) {
for(int j=1;j<=col;j++) s[i][j]=x[i][j];
}
}
}Init(2),seq(2,1);
void init() {
int I[N][N],S[N][N];
memset(I,0,sizeof(I));
memset(S,0,sizeof(S));
I[1][1]=I[1][2]=I[2][1]=S[1][1]=S[2][1]=1;
Init.init(I);
seq.init(S);
}
Matrix qpow(Matrix x,ll y) {
Matrix a;
Matrix b(2);
a=x;
b.idenitity();
while(y) {
if(y&1) b*=a;
a*=a;
y>>=1;
}
return b;
}
int main() {
cin>>n;
if(n<=2) cout<<1<<endl;
else {
init();
Init=qpow(Init,n-2);
seq=Init*seq;
seq.printp();
}
return 0;
}
如果不是斐波那契数列呢?
[洛谷P1939]【模板】矩阵加速(数列)
已知一个数列
求
数据范围
数据组数
链接
P1939 【模板】矩阵加速(数列)
思路
考虑这样一个矩阵
显然
于是可以矩阵快速幂加速。即
代码
#include<bits/stdc++.h>
#define N 5
#define ll long long
#define mod 1000000007
using namespace std;
int T;
class Matrix{
private:
int row,col;
ll s[N][N];
public:
Matrix() {
row=col=0;
memset(s,0,sizeof(s));
}
Matrix(int _row,int _col):row(_row),col(_col){memset(s,0,sizeof(s));}
Matrix(int n):row(n),col(n){memset(s,0,sizeof(s));}
Matrix operator * (Matrix x) {
Matrix y(row,x.col);
for(int i=1;i<=row;i++) {
for(int j=1;j<=x.col;j++) {
for(int k=1;k<=col;k++) y.s[i][j]=(y.s[i][j]+s[i][k]*x.s[k][j])%mod;
}
}
return y;
}
Matrix operator *= (Matrix x) {
return *this=*this*x;
}
void idenitity() {
for(int i=1;i<=row;i++) s[i][i]=1;
}
void printp() {
cout<<s[1][1]<<endl;
}
void init(int x[][N]) {
for(int i=1;i<=row;i++) {
for(int j=1;j<=col;j++) s[i][j]=x[i][j];
}
}
}Init(3),seq(3,1);
void init() {
int I[N][N],S[N][N];
memset(I,0,sizeof(I));
memset(S,0,sizeof(S));
I[1][1]=I[1][3]=I[2][1]=I[3][2]=S[1][1]=S[2][1]=S[3][1]=1;
Init.init(I);
seq.init(S);
}
Matrix qpow(Matrix x,int y) {
Matrix a;
Matrix b(3);
a=x;
b.idenitity();
while(y) {
if(y&1) b*=a;
a*=a;
y>>=1;
}
return b;
}
int main() {
cin>>T;
init();
while(T--) {
int n;
cin>>n;
if(n<=3) cout<<1<<endl;
else {
Matrix a,b;
a=qpow(Init,n-3);
b=a*seq;
b.printp();
}
}
return 0;
}
推广
如果是更一般的数列呢?
考虑这样一个数列
可以构造出一个矩阵
显然
其实很好构造出来的。
右下角甚至是个杨辉三角
完。