超級計算機計算效率非常快,小明購買了一臺超級計算機,用超級計算機生成一個巨大的矩陣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; }