巨大的矩陣(矩陣加速)

cn是大帅哥886發表於2024-08-16
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

樣例解釋

image.png

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;
}

  

相關文章