先从最基础的矩阵快速幂加速递推开始。
HDU 1005 Number Sequence
|f[n-2],f[n-1]|* |0 B| =|f[n-1], B*f[n-2]+A*f[n-1]|=|f[n-1],f[n]|
|1 A|
建立矩阵如上然后利用快速幂求解即可。答案是mat[0][1]。
#include<iostream> #include<vector> #include<cmath> #include<map> #include<algorithm> #include<cstring> #include<cstdio> #include<cstdlib> #include<queue> #include<cmath> #include<set> #include<string> #define INF 1000000005 #define LL long long using namespace std; const int MAXN =5; struct Matrix { int n,m; int a[MAXN][MAXN]; void clear(int x=0,int y=0) { n=x; m=y; memset(a,0,sizeof(a)); } Matrix operator * (const Matrix &b)const { Matrix tmp; tmp.clear(n,b.m); for(int i=0; i<n; ++i) for(int j=0; j<b.m; ++j) for(int k=0; k<m; ++k) { tmp.a[i][j]+=a[i][k]*b.a[k][j]; tmp.a[i][j]%=7; } return tmp; } }; Matrix quickPow(Matrix mat,int n) { Matrix res; res.clear(2,2); res.a[0][0]=res.a[1][1]=1; while(n) { if(n&1) res=res*mat; mat=mat*mat; n=n>>1; } return res; } int main() { int A,B,n; while(scanf("%d%d%d",&A,&B,&n)!=EOF) { if(!A&&!B&&!n) break; if(n==1||n==2) { puts("1"); continue; } Matrix mat; mat.clear(2,2); mat.a[0][0]=0; mat.a[0][1]=B; mat.a[1][0]=1; mat.a[1][1]=A; Matrix f; f.clear(1,2); f.a[0][0]=1; f.a[0][1]=1; n-=2; Matrix s=f*quickPow(mat,n); printf("%d\n",(s.a[0][1])%7); } return 0; }
HDU 4920 Matrix multiplication
矩阵乘法,直接算会超时。由于是模3,所以0很多,也就是稀疏矩阵。可以优化。
参见下文:http://www.cnblogs.com/jackiesteed/articles/2021604.html
#include<iostream> #include<vector> #include<map> #include<cmath> #include<algorithm> #include<cstring> #include<cstdio> #include<cstdlib> #include<string> #define LL long long using namespace std; int A[805][805],B[805][805]; int C[805][805]; int n; int main() { int n; while(scanf("%d",&n)!=EOF) { for(int i=1; i<=n; ++i) for(int j=1; j<=n; ++j) { scanf("%d",&A[i][j]); A[i][j]%=3; } for(int i=1; i<=n; ++i) for(int j=1; j<=n; ++j) { scanf("%d",&B[i][j]); B[i][j]%=3; } memset(C,0,sizeof(C)); for(int i=1; i<=n; ++i) for(int j=1; j<=n; ++j) { if(A[i][j]==0) continue; for(int k=1; k<=n; ++k) C[i][k]+=A[i][j]*B[j][k]; } for(int i=1; i<=n; ++i) { for(int j=1; j<=n; ++j) if(j==1) printf("%d",C[i][j]%3); else printf(" %d",C[i][j]%3); printf("\n"); } } return 0; }
HDU 1575 Tr A
求矩阵的迹。直接快速幂即可。
#include<iostream> #include<vector> #include<cmath> #include<map> #include<algorithm> #include<cstring> #include<cstdio> #include<cstdlib> #include<queue> #include<cmath> #include<set> #include<string> #define INF 1000000005 #define LL long long using namespace std; const int MAXN =12; struct Matrix { int n,m; int a[MAXN][MAXN]; void clear(int x=0,int y=0) { n=x; m=y; memset(a,0,sizeof(a)); } Matrix operator * (const Matrix &b)const { Matrix tmp; tmp.clear(n,b.m); for(int i=0; i<n; ++i) for(int j=0; j<b.m; ++j) { for(int k=0; k<b.m; ++k) { if(0==a[i][j]) continue;//优化! tmp.a[i][k]+=a[i][j]*b.a[j][k]; tmp.a[i][k]%=9973; } } return tmp; } void setOne(int x) { clear(x,x); for(int i=0; i<x; ++i) a[i][i]=1; } }; Matrix one; Matrix quickPow(Matrix mat,int n) { Matrix res=one; while(n) { if(n&1) res=res*mat; mat=mat*mat; n=n>>1; } return res; } int main() { int T; scanf("%d",&T); while(T--){ int n,k; scanf("%d%d",&n,&k); one.setOne(n); Matrix mat; mat.clear(n,n); for(int i=0;i<n;++i) for(int j=0;j<n;++j) scanf("%d",&mat.a[i][j]); mat=quickPow(mat,k); int ans=0; for(int i=0;i<n;++i) { ans+=mat.a[i][i]; ans%=9973; } printf("%d\n",ans); } return 0; }
HDU 1757 A Simple Math Problem
一个简单的递推,建立矩阵后,快速幂。
#include<iostream> #include<vector> #include<cmath> #include<map> #include<algorithm> #include<cstring> #include<cstdio> #include<cstdlib> #include<queue> #include<cmath> #include<set> #include<string> #define INF 1000000005 #define LL long long using namespace std; const int MAXN =12; int M; struct Matrix { int n,m; int a[MAXN][MAXN]; void clear(int x=0,int y=0) { n=x; m=y; memset(a,0,sizeof(a)); } Matrix operator * (const Matrix &b)const { Matrix tmp; tmp.clear(n,b.m); for(int i=0; i<n; ++i) for(int j=0; j<b.m; ++j) { for(int k=0; k<b.m; ++k) { if(0==a[i][j]) continue;//优化! tmp.a[i][k]+=a[i][j]*b.a[j][k]; tmp.a[i][k]%=M; } } return tmp; } void setOne(int x) { clear(x,x); for(int i=0; i<x; ++i) a[i][i]=1; } }; Matrix one; Matrix quickPow(Matrix mat,int n) { Matrix res=one; while(n) { if(n&1) res=res*mat; mat=mat*mat; n=n>>1; } return res; } int main() { int k; one.setOne(10); while(scanf("%d%d",&k,&M)!=EOF) { Matrix mat; mat.clear(10,10); for(int i=0; i<9; ++i) mat.a[i+1][i]=1; for(int i=0; i<10; ++i) scanf("%d",&mat.a[9-i][9]); if(k<10) printf("%d\n",k%M); else { Matrix f; f.clear(1,10); for(int i=0; i<10; ++i) f.a[0][i]=i; k-=9; f=f*quickPow(mat,k); printf("%d\n",f.a[0][9]); } } return 0; }
UVa 10870 Recurrences
与上面类型相似的题,建立矩阵,再快速幂加速。注意会超int。
#include<iostream> #include<vector> #include<cmath> #include<map> #include<algorithm> #include<cstring> #include<cstdio> #include<cstdlib> #include<queue> #include<cmath> #include<set> #include<string> #define INF 1000000005 #define LL long long using namespace std; const int MAXN =20; int M; struct Matrix { int n,m; LL a[MAXN][MAXN]; void clear(int x=0,int y=0) { n=x; m=y; memset(a,0,sizeof(a)); } Matrix operator * (const Matrix &b)const { Matrix tmp; tmp.clear(n,b.m); for(int i=0; i<n; ++i) for(int j=0; j<b.m; ++j) { for(int k=0; k<b.m; ++k) { if(0==a[i][j]) continue;//优化! tmp.a[i][k]+=a[i][j]*b.a[j][k]; tmp.a[i][k]%=M; } } return tmp; } void setOne(int x) { clear(x,x); for(int i=0; i<x; ++i) a[i][i]=1; } }; Matrix one; Matrix quickPow(Matrix mat,LL n) { Matrix res=one; while(n) { if(n&1) res=res*mat; mat=mat*mat; n=n>>1; } return res; } int main() { int d,n; while(scanf("%d%d%d",&d,&n,&M)!=EOF) { if(!d&&!n&&!M) break; one.setOne(d); Matrix mat; mat.clear(d,d); for(int i=0; i<d; ++i) mat.a[i+1][i]=1; for(int i=0; i<d; ++i) scanf("%lld",&mat.a[d-1-i][d-1]); Matrix f; f.clear(1,d); for(int i=0; i<d; ++i) scanf("%lld",&f.a[0][i]); if(n<=d) printf("%lld\n",f.a[0][n-1]%M); else { n-=d; f=f*quickPow(mat,n); printf("%lld\n",f.a[0][d-1]%M); } } return 0; }
POJ 3734 Blocks
递推+矩阵快速幂。
设计状态的时候要考虑所有可能的情况,保证无重复无遗漏,再考虑转移。最后用矩阵加速。
#include<iostream> #include<vector> #include<cmath> #include<map> #include<algorithm> #include<cstring> #include<cstdio> #include<cstdlib> #include<queue> #include<cmath> #include<set> #include<string> #define INF 1000000005 #define LL long long using namespace std; const int MAXN =4; int M=10007; struct Matrix { int n,m; int a[MAXN][MAXN]; Matrix(int x=0,int y=0):n(x),m(y) { memset(a,0,sizeof(a)); } void clear(int x=0,int y=0) { n=x; m=y; memset(a,0,sizeof(a)); } Matrix operator * (const Matrix &b)const { Matrix tmp; tmp.clear(n,b.m); for(int i=0; i<n; ++i) for(int j=0; j<b.m; ++j) { for(int k=0; k<b.m; ++k) { if(0==a[i][j]) continue;//ÓÅ»¯£¡ tmp.a[i][k]+=a[i][j]*b.a[j][k]; tmp.a[i][k]%=M; } } return tmp; } void setOne(int x) { clear(x,x); for(int i=0; i<x; ++i) a[i][i]=1; } }; Matrix one; Matrix quickPow(Matrix mat,int n) { Matrix res=one; while(n) { if(n&1) res=res*mat; mat=mat*mat; n=n>>1; } return res; } int main() { one.setOne(3); int T; scanf("%d",&T); while(T--) { int n; scanf("%d",&n); Matrix mat(3,3); mat.a[0][0]=2,mat.a[0][1]=1,mat.a[0][2]=0; mat.a[1][0]=2,mat.a[1][1]=2,mat.a[1][2]=2; mat.a[2][0]=0,mat.a[2][1]=1,mat.a[2][2]=2; Matrix f(3,1); f.a[0][0]=1; Matrix ans=f*quickPow(mat,n); printf("%d\n",ans.a[0][0]); } return 0; }
ACM 矩阵题目整理
时间: 2024-10-15 12:44:36