洛谷P1397 [NOI2013]矩阵游戏

题意链接

题意简述

给定一个二维的递推方程,已知第一项\((1,1)\)求其第\((n,m)\)

分析

一道矩阵乘法基础题

一看到递推式还没有特殊条件就知道是矩阵快速幂

但是这个\(n,m\)的范围着实是不正常

所以考虑到要用个某某定理或者性质把\(n,m\)的范围缩小

这里就是费马小定理了

容易发现,这里的矩阵乘法是满足费马小定理的,但是当\(a=1\)的情况要特判,(至于为什么详见这篇博客或者这篇博客

所以接下来我们可以开始构造状态矩阵

构造状态转移矩阵的方法:若状态矩阵中第 \(x\) 个数对下一单位时间状态矩阵中第 \(y\) 个数有影响,则把转移矩阵的第 \(x\)行第 \(y\) 列赋值为适当的系数。

我们发现,状态矩阵中第一个数要乘\(a\)\(b\),那么根据上面的定义很容易想到,状态转移矩阵的第一列分别就是 \(a\)\(b\),分别对应\(f_{(i-1,j)}\)\(1\)。我们会发现状态矩阵中第二个值是不变的,它赋值为 \(1\) 的意义在于能够刚好计算最后的 \(+b\)

所以我们可以把单独一行的转移方程写出来:

\(\left\{ \begin{matrix} a & 0\\ b & 1 \end{matrix} \right\}\)

那么其实我们每一行转移过后就是行与行之间的转移,那么我们可以把这个转移方程也直接写出来:

\(\left\{ \begin{matrix} c & 0\\ d & 1 \end{matrix} \right\}\)

(其实一点变化都没有)

所以我们手摸一下,可以直接得出:

我们的初始状态的矩阵要乘上

\[\left[ \begin{matrix} a & 0\\ b & 1 \end{matrix} \right]^{(m-1)*n} * \left[ \begin{matrix} c & 0\\ d & 1 \end{matrix} \right]^{(n-1)} \]

最后答案就是初始矩阵的元素\(f_{(1,1)}\)

那么这道题就结束了

代码

代码附上

#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
	x=0;char ch=getchar();bool f=false;
	while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	x=f?-x:x;
	return ;
}
template <typename T>
inline void write(T x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10^48);
	return ;
}
#define ll long long
const ll MOD=1e9+7,N=1e6+5;
#define inc(a,b) (a+b>=MOD?a+b-MOD:a+b)
struct Matrix{
	ll a[3][3];
	Matrix(){memset(a,0,sizeof(a));}
	Matrix operator * (Matrix B){
		Matrix C;
		for(int i=1;i<3;i++){
			for(int j=1;j<3;j++){
				for(int k=1;k<3;k++){
					C.a[i][j]=inc(C.a[i][j],a[i][k]*B.a[k][j]%MOD);
				}
			}
		}
		return C;
	}
};
Matrix QuickPow(Matrix A,ll y){
	Matrix res;
	res.a[1][1]=res.a[2][2]=1;
	while(y){
		if(y&1) res=res*A;
		A=A*A;
		y>>=1;
	}
	return res;
}
Matrix ans,base,base1;
string nn,mm;
ll a,b,c,d,n,m;
int main(){
	cin>>nn>>mm>>a>>b>>c>>d;
	int len1,len2;
	len1=nn.size(),len2=mm.size(); 
	for(int i=0;i<len1;i++) n=(n*10+nn[i]-'0')%(a==1?MOD:MOD-1);
	for(int i=0;i<len2;i++) m=(m*10+mm[i]-'0')%(a==1?MOD:MOD-1);
	ans.a[1][1]=1,ans.a[1][2]=1;
	base.a[1][1]=a,base.a[2][1]=b,base.a[2][2]=1;
	base=QuickPow(base,m-1);
	base1.a[1][1]=c,base1.a[2][1]=d,base1.a[2][2]=1;
	base=base*base1;
	base=QuickPow(base,n-1);
	base1.a[1][1]=a,base1.a[2][1]=b,base1.a[2][2]=1;
	base1=QuickPow(base1,m-1);
	write((ans*(base*base1)).a[1][1]);
	return 0;
}

posted @ 2020-12-06 15:38  __Anchor  阅读(96)  评论(0编辑  收藏  举报