矩阵(板子)
文章目录
- 一、前言
- 二、算法
- <1>P3390 (【模板】矩阵快速幂)
- <2> P1939 (矩阵加速(数列))
- <3> P1306 (斐波那契公约数)
- 三、总结
一、前言
//一些矩阵乘法
二、算法
<1>P3390 (【模板】矩阵快速幂)
题解:
给定一个矩阵,求它的k次方
因为矩阵本身的乘法运算满足交换律和结合律,所以思考发现也应该满足快速幂的二的幂次相乘的规律。
对应一般的快速幂,写一个矩阵快速幂的函数,重新定义乘法,注意传参问题即可。
代码:
#include<bits/stdc++.h>using namespace std;
#define int long longconst int mod = 1e9+7;
const int N = 110;
int n,k;
int a[N][N];int qpow(int base,int power) {int res = 1;while(power) {if(power & 1) res = res*base%mod;base = base*base%mod;power >>= 1;}return res;
}//一般快速幂void chen(int ra[][N],int rb[][N]) {int ls[N][N];for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {for (int lk = 1; lk <= n; lk++) {ls[i][j] += (ra[i][lk]*rb[lk][j]%mod);ls[i][j] %= mod;//cout << ra[i][lk] << ' ' << rb[lk][j] << endl;}//cout << i << '/' << j << endl;}}for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {ra[i][j] = ls[i][j];ls[i][j] = 0;}}
}//矩阵乘法方式,ra数组会被传回去int ans[N][N];
void qpow_jz(int power) {while(power) {if(power & 1) chen(ans,a);chen(a,a);power >>= 1;}return ;
}//求矩阵a的power次方void solve() {cin >> n >> k;for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {cin >> a[i][j];}}for (int i = 1; i <= n; i++) {ans[i][i] = 1;}//单位矩阵qpow_jz(k);for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {cout << ans[i][j] << ' ';}cout << endl;}
}signed main() {ios::sync_with_stdio(false);cin.tie(0); cout.tie(0);int _ = 1;//cin >> _;while(_--) solve();
}
<2> P1939 (矩阵加速(数列))
题解:
给了一个f数组的递推式,要求第n项,n高达2e9.
真是没想到跟矩阵有什么关系,看了题解发现可以考虑整体递推,这样就是一个不断相乘的过程。
【f[3],f[2],f[1]】(竖着摆放)
f[4] = f[3]+f[1]
f[3] = f[3]
f[2] = f[2]
根据矩阵相乘的规律,可以得到矩阵A
[1,0,1
1,0,0
0,1,0]
这是一次递推式,如果需要多次递推,也就是矩阵A的快速幂,快速幂n次之后发现ans[2][1]就是所需要的答案。
代码:
#include<bits/stdc++.h>using namespace std;
#define int long longconst int mod = 1e9+7;
const int N = 5;
int n = 3;
int k;
int a[N][N];int qpow(int base,int power) {int res = 1;while(power) {if(power & 1) res = res*base%mod;base = base*base%mod;power >>= 1;}return res;
}//一般快速幂void chen(int ra[][N],int rb[][N]) {int ls[N][N];memset(ls,0,sizeof ls);for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {for (int lk = 1; lk <= n; lk++) {ls[i][j] += (ra[i][lk]*rb[lk][j]%mod);ls[i][j] %= mod;//cout << ra[i][lk] << ' ' << rb[lk][j] << endl;}//cout << i << '/' << j << endl;//cout << ls[i][j] << endl;}}for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {ra[i][j] = ls[i][j];ls[i][j] = 0;}}
}int ans[N][N];
void qpow_jz(int power) {//求矩阵a的power次方while(power) {if(power & 1) chen(ans,a);chen(a,a);power >>= 1;}return ;
}void solve() {cin >> k;if(k <= 3) {cout << 1 << endl;return ;}memset(a,0,sizeof a);memset(ans,0,sizeof a);a[1][1] = a[1][3] = a[2][1] = a[3][2] = 1;for (int i = 1; i <= n; i++) {ans[i][i] = 1;}//单位1qpow_jz(k);cout << ans[2][1] << endl;}signed main() {ios::sync_with_stdio(false);cin.tie(0); cout.tie(0);int _ = 1;cin >> _;while(_--) solve();
}
<3> P1306 (斐波那契公约数)
题解:
主要需要考虑到一开始的n就会超过1e8,所以直接mod 会有误差,经过一系列推算,发现先求公约数再算斐波那契数和原本所要求的是一样的,所以计算出转移矩阵后用矩阵快速幂即可。
代码:
#include<bits/stdc++.h>using namespace std;
#define int long longconst int mod = 1e8;
const int N = 5;
int n = 2;
int k;
int a[N][N];int qpow(int base,int power) {int res = 1;while(power) {if(power & 1) res = res*base%mod;base = base*base%mod;power >>= 1;}return res;
}//一般快速幂void chen(int ra[][N],int rb[][N]) {int ls[N][N];memset(ls,0,sizeof ls);for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {for (int lk = 1; lk <= n; lk++) {ls[i][j] += (ra[i][lk]*rb[lk][j]%mod);ls[i][j] %= mod;//cout << ra[i][lk] << ' ' << rb[lk][j] << endl;}//cout << i << '/' << j << endl;//cout << ls[i][j] << endl;}}for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {ra[i][j] = ls[i][j];ls[i][j] = 0;}}
}int ans[N][N];
void qpow_jz(int power) {//求矩阵a的power次方while(power) {if(power & 1) chen(ans,a);chen(a,a);power >>= 1;}return ;
}int gcd(int x,int y) {return y ? gcd(y,x%y):x;
}int rx,ry;void solve() {cin >> rx >> ry;int k = gcd(rx,ry);if(k <= 2) {if(rx == 0) rx = 1;else ry = 1;return ;}memset(a,0,sizeof a);memset(ans,0,sizeof a);a[1][1] = a[1][2] = a[2][1] = 1;for (int i = 1; i <= n; i++) {ans[i][i] = 1;}//单位1qpow_jz(k);
// for(int i = 1; i <= n; i++) {
// for (int j = 1; j <= n; j++) {
// cout << ans[i][j] << ' ';
// }cout << endl;
// }cout << ans[2][1] << endl;
}signed main() {ios::sync_with_stdio(false);cin.tie(0); cout.tie(0);int _ = 1;// cin >> _;while(_--) solve();
}
