矩阵快速幂(14)
2020-02-02 19:45
225 查看
矩阵快速幂
先说明一下:看到矩阵快速幂,我先想到的是快速幂,后来感觉差不多。
不会快速幂的可以先看一下这篇:快速幂
废话不多说,直接上板子:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int mod=10000; //先不用管这个,一做题就明白了 int f=2; struct node { ll materix[5][5]; }; node mul(node a,node b) //矩阵乘法 { node res; memset(res.materix,0,sizeof res.materix); for(int i=1;i<=f;i++) for(int j=1;j<=f;j++) for(int k=1;k<=f;k++) res.materix[i][j]=(res.materix[i][j]+a.materix[i][k]*b.materix[k][j])%mod; return res; } node ksm(node a,ll b) //快速幂 { node ans; memset(ans.materix,0,sizeof ans.materix); for(int i=1;i<=f;i++) ans.materix[i][i]=1; while(b) { if(b&1) ans=mul(ans,a); b>>=1; a=mul(a,a); } return ans; }
大体就是上面那套板子,按照小编目前短浅的理解,矩阵快速幂的难度在于找到最初始的矩阵和乘的矩阵…
来几个板子题:
传送门:Fibonacci POJ - 3070
很明显直接算不现实,这时候就得用到矩阵快速幂,这里就是那个mod的作用
//#include<bits/stdc++.h> #include <iostream> #include<cstring> #include<stdio.h> using namespace std; typedef long long ll; const int mod=10000; int f=2; struct node { ll materix[5][5]; }; node mul(node a,node b) //矩阵乘法 { node res; memset(res.materix,0,sizeof res.materix); for(int i=1;i<=f;i++) for(int j=1;j<=f;j++) for(int k=1;k<=f;k++) res.materix[i][j]=(res.materix[i][j]+a.materix[i][k]*b.materix[k][j])%mod; return res; } node ksm(node a,ll b) { node ans; memset(ans.materix,0,sizeof ans.materix); for(int i=1;i<=f;i++) ans.materix[i][i]=1; while(b) { if(b&1) ans=mul(ans,a); b>>=1; a=mul(a,a); } return ans; } int main() { ll N; while(cin>>N&&N!=-1) { if(N==1||N==2) printf("1\n"); if(N==0) printf("0\n"); else { node a,b; a.materix[1][1]=1; a.materix[1][2]=1; a.materix[2][1]=1; a.materix[2][2]=0; //a是那个幂矩阵, b.materix[1][1]=1; b.materix[1][2]=0; b.materix[2][1]=1; b.materix[2][2]=0; //b是最初始的矩阵 //假如a*a*a*b就是a^3*b,所以先求用快速幂求a的三次方,再用结果和b相乘 //注意乘的顺序,矩阵相乘a*b!=b*a,顺序不能搞错 //这里个人有个小诀窍,因为.f(n)=a*f(n-1)+b*f(n-2)+c,所以前边的那个应该是构造矩阵 node ans = ksm(a ,N-2); //从3开始,所以-2 ans = mul(ans ,b) ; printf("%d\n",ans.materix[1][1] ) ; } } return 0; }
传送门: Tr A HDU - 1575
一模一样的板子题
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll n,k; int mod=9973; struct node { ll materix[11][11]; }; node mul(node a,node b) //矩阵乘法 { node res; memset(res.materix,0,sizeof res.materix); for(int i=0;i<n;i++) for(int j=0;j<n;j++) for(int k=0;k<n;k++) res.materix[i][j]=(res.materix[i][j]+a.materix[i][k]*b.materix[k][j])%mod; return res; } node ksm(node a,ll b) { node ans; memset(ans.materix,0,sizeof ans.materix); for(int i=0;i<n;i++) ans.materix[i][i]=1; while(b) { if(b&1) ans=mul(ans,a); b>>=1; a=mul(a,a); } return ans; } int main() { int T; cin>>T; while(T--) { cin>>n>>k; node c; for(int i=0;i<n;i++) for(int j=0;j<n;j++) cin>>c.materix[i][j]; node ans=ksm(c,k); int sum=0; for(int i=0;i<n;i++) sum=sum+ans.materix[i][i]%mod; printf("%d\n",sum%mod); } return 0; }
传送门: A Simple Math Problem HDU - 1757
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll k,m; int aa[15]; struct node { ll materix[15][15]; }; node mul(node a,node b) //矩阵乘法 { node res; memset(res.materix,0,sizeof res.materix); for(int i=1;i<=10;i++) for(int j=1;j<=10;j++) for(int k=1;k<=10;k++) res.materix[i][j]=(res.materix[i][j]+a.materix[i][k]*b.materix[k][j])%m; return res; } node ksm(node a,ll b) { node ans; memset(ans.materix,0,sizeof ans.materix); for(int i=1;i<=10;i++) ans.materix[i][i]=1; while(b) { if(b&1) ans=mul(ans,a); b>>=1; a=mul(a,a); } return ans; } int main() { while(~scanf("%lld %lld",&k,&m)) { if(k<10) { cout<<k%m<<endl; continue; } else { node a,b; for(int i=0;i<=15;i++) for(int j=0;j<=15;j++) a.materix[i][j]=b.materix[i][j]=0; for(int i=1;i<=10;i++) cin>>a.materix[1][i]; for(int i=1;i<=9;i++) a.materix[i+1][i]=1; for(int i=1;i<=10;i++) b.materix[i][1]=10-i; node ans=ksm(a,k-9); ans=mul(ans,b); printf("%d\n",ans.materix[1][1]%m); } } return 0; }
传送门: Recursive sequence HDU - 5950(矩阵的构造)
这应该是一个简单的矩阵构造,希望读者能认认真真的学会如何构造一个矩阵。
这个题的构造难在构造矩阵当时构造出来后就懒得写板子了,所以直接CV代码。
关于这个题,读者应该去百度如何构造矩阵,去学习多种矩阵的构造方法以防万一。
#include<stdio.h> #include<string.h> using namespace std; #define ll long long const ll maxn = 7; const ll mod = 2147493647; struct mat { ll m[maxn][maxn]; }; mat operator *(mat x, mat y) { mat ret; for(int i = 0; i < maxn; i++) { for(int j = 0; j < maxn; j++) { ret.m[i][j] = 0; for(int k = 0; k < maxn; k++) { ret.m[i][j] = (x.m[i][k] * y.m[k][j] + ret.m[i][j]) % mod; } } } return ret; } mat pow_mat(mat a, ll fuck) { mat ret; memset(ret.m,0,sizeof(ret.m)); for(int i = 0; i < maxn; i++) ret.m[i][i] = 1; while(fuck) { if(fuck&1) ret = ret*a; a = a*a; fuck >>= 1; } return ret; } int main() { int t; scanf("%d",&t); while(t--) { ll f1, f2, m; scanf("%lld%lld%lld",&m,&f1,&f2); if(m == 1) printf("%lld\n",f1); else if(m == 2) printf("%lld\n",f2); else { mat a; memset(a.m,0,sizeof(a.m)); a.m[0][0] = f2; a.m[1][0] = f1; a.m[2][0] = 1; a.m[3][0] = 2; a.m[4][0] = 4; a.m[5][0] = 8; a.m[6][0] = 16; mat b = { 1, 2, 1, 4, 6, 4, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 1, 3, 3, 1, 0, 0, 0, 1, 4, 6, 4, 1 }; a = pow_mat(b,m-2)*a; printf("%lld\n",a.m[0][0]); } } return 0; }
还有三个水题…读者可以用来练手
传送门:1126 求递推序列的第N项
传送门:1113 矩阵快速幂
传送门:1137 矩阵乘法
- 点赞
- 收藏
- 分享
- 文章举报
相关文章推荐
- Bell(矩阵快速幂+中国剩余定理)
- 【BZOJ2326】[HNOI2011]数学作业【矩阵快速幂】
- 矩阵快速幂
- hdu2157 How many ways??(矩阵快速幂
- hdu1757 A Simple Math Problem 矩阵快速幂 水题
- 稀疏矩阵的列序递增法和一次定位快速转置法
- HDU 3306 矩阵快速幂
- hdu 4549 M斐波那契数列 【矩阵+快速幂+欧拉定理】
- hdu5690All X 「矩阵快速幂」
- Codeforces Round #118 (Div. 2) :C (矩阵快速幂)类似与斐波那契+矩阵乘法
- 矩阵快速乘法---代码
- 稀疏矩阵的相关操作(存储、转置、快速转置、相加)
- hdu 1757 A Simple Math Problem(矩阵快速幂)
- 2019牛客多校第五场B-generator 1(矩阵快速幂)
- HDU 4549 M斐波那契数列(矩阵快速幂&费马小定理)
- [SCU 4508] 雷神之路 (多矩阵快速幂)
- ZOJ 2317 Nice Patterns Strike Back(矩阵快速幂)
- 【矩阵快速幂】经典题 hdu2157 how many ways、woj642 Lost In WHU
- HDU 1575 Tr A(矩阵快速幂)
- 【矩阵快速幂】 斐波那契数列求解。