https://www.luogu.com.cn/problem/P1397 第2题 巨大的矩阵 查看测评数据信息
超级计算机计算效率非常快,小明购买了一台超级计算机,用超级计算机生成一个巨大的矩阵A,矩阵A有n行m列的矩阵。A[i][j]表示矩阵A第i行第j列的元素,超级计算机生成矩阵A满足如下性质:A[1][1]=1,
A[i][j]=a*A[i][j-1]+b (j!=1),
A[i][1]=c*A[i-1][m]+d (i!=1)。
其中a,b,c,d都是常数。超级计算机计算出的A[n][m]的值是多少?,结果可能很大,对1000000007取模。
输入格式
第一行六个整数n,m,a,b,c,d
1<=n,m,a,b,c,d<=1e9
输出格式
一个整数,对1000000007取模
输入/输出例子1
输入:
3 4 1 3 2 6
输出:
85
样例解释
1.对于有规律性的矩阵处理(这个分析到后面才能慢慢发现规律),考虑分段处理
2.第一次看题就是看是否是一次性无法处理的矩阵,如果一次性无法很好处理,也考虑分段处理
由于题目有两个递推式子,且是相互关联的,一个矩阵没法很好解决。我们分开处理两个矩阵。分个段处理
对于列:f(i, j)=a*f(i, j-1)+b
我们已知肯定有j-1,但是单凭这一个条件不够推,+b没法满足,所以补一个1
[f(i, j-1), 1] * [ A ] = [f[i, j], 1]
所以可以推出A矩阵
[a, 0]
[b, 1]
对于行:f(i, 1)=c*f(i-1, m)+d
跟列一样,补一个1
[f(i-1, m), 1] * [ B ] = [f[i, 1], 1]
可以推出B矩阵
[c, 0]
[d, 1]
分别处理完之后,我们可以处理每一行的值分别是多少,并发现这其实是一个规律!
第一行+第二行第一个数 A^(m-1) · B
第二行+第三行第一个数 A^(m-1) · B
.......
第n行+第n+1行第一个数 A^(m-1) · B
那不就出来了吗,我们对这个式子进行快速幂即可,注意是n-1次,然后再乘A矩阵,因为直接乘n次算的是第n+1行第一个数的值
答案:
(A^(m-1)·B ) ^ (n-1) * A^(m-1)
对于这题,我们最后发现是有规律性的,所以我们分了两段,分段处理
#include <bits/stdc++.h> #define int long long using namespace std; const int N=105, Mod=1000000007; struct mp { int n, m; int a[N][N]; void init(int row, int col, bool isI) { n=row, m=col; memset(a, 0, sizeof a); if (isI) for (int i=1; i<=row; i++) a[i][i]=1; } }A, B, C; mp operator * (const mp A, const mp B) { mp C; C.init(A.n, B.m, 0); for (int i=1; i<=A.n; i++) for (int j=1; j<=B.m; j++) for (int k=1; k<=A.m; k++) C.a[i][j]=(C.a[i][j]+A.a[i][k]*B.a[k][j])%Mod; return C; } mp qpow_mp(mp A, int k) { mp res; res.init(A.n, A.m, 1); while (k>0) { if (k&1) res=res*A; A=A*A; k>>=1; } return res; } int n, m, a, b, c, d; signed main() { scanf("%lld%lld%lld%lld%lld%lld", &n, &m, &a, &b, &c, &d); A.init(1, 2, 0); A.a[1][1]=1, A.a[1][2]=1; B.init(2, 2, 0); B.a[1][1]=a, B.a[1][2]=0; B.a[2][1]=b, B.a[2][2]=1; C.init(2, 2, 0); C.a[1][1]=c, C.a[1][2]=0; C.a[2][1]=d, C.a[2][2]=1; A=A*qpow_mp(qpow_mp(B, m-1)*C, n-1)*qpow_mp(B, m-1); printf("%lld", A.a[1][1]); return 0; }
标签:int,超级计算机,矩阵,巨大,处理,init,lld%,加速 From: https://www.cnblogs.com/didiao233/p/18363698