巨大的矩阵(矩阵加速)
超级计算机计算效率非常快,小明购买了一台超级计算机,用超级计算机生成一个巨大的矩阵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(这里不要直接补b,而是补1,不然后面一个矩阵也要借助这个初始矩阵去计算,如果改成b后面那么矩阵就算不了了!!!)
[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;
}

浙公网安备 33010602011771号