其他分享
首页 > 其他分享> > 矩阵游戏

矩阵游戏

作者:互联网

矩阵游戏

是一道题;
正好拿来练矩阵乘法;

题目传送门 https://www.luogu.com.cn/problem/P1397

显然老老实实的递推挂了;
那么 很容易想到矩阵加速
如何从F(1,1)转换到F(n,m)
每一列进行m-1次乘a加b的操作A
每一行进行n-1次乘c加d的操作B

可得 F(i,n)=F(i,1)* ( A^(m-1)); (^表示次方)
同理
每一行F(n,1)=F(1,1)*(B^(n-1);
对于每一项记为ans,开始时为|1 , 1|

每一行递推项A, 则为
|a , 0|
|b , 1|
同理每一列B,则为
|c , 0|
|d , 1| 矩阵乘法手推一下啦;
由此可得
F(n,m)=F(1,1)* [(A(m-1)***B**)(n-1)] * A^(m-1)

有了大好的公式,接下来就是喜闻乐见的代码了

#include<bits/stdc++.h>
#define mod 1000000007
#define phi 1000000006
using namespace std;
typedef long long ll;
string n,m;
ll a,b,c,d;
struct Matrix
{ 
	ll a[5][5]; 
	Matrix() {memset(a,0,sizeof(a));}
};
Matrix mul(Matrix A,Matrix B)
{
	Matrix ans;
	for(int i=1;i<=2;i++)
		for(int j=1;j<=2;j++)
			for(int k=1;k<=2;k++)
			{
				ans.a[i][j]+=(A.a[i][k]*B.a[k][j])%mod;
				ans.a[i][j]%=mod;	
			}
	return ans;
}
Matrix qpow(Matrix a,ll b)
{
	Matrix tmp;
	for(int i=1;i<=2;i++) tmp.a[i][i]=1;
	for(;b;b>>=1)
	{
		if(b&1) tmp=mul(tmp,a);
		
		a=mul(a,a);
	}
	return tmp;
}

int main()
{
	cin>>n>>m;
	Matrix A,B,ans,Ans;
	scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
	ll ln=n.size(),lm=m.size(),nans=0,mans=0;
	
	Ans.a[1][1]=1; Ans.a[1][2]=1;
	A.a[1][1]=a, A.a[1][2]=0, A.a[2][1]=b, A.a[2][2]=1;
	B.a[1][1]=c, B.a[1][2]=0, B.a[2][1]=d, B.a[2][2]=1;
	
	for(int i=0;i<ln;i++)
	nans=(nans<<3)+(nans<<1)+n[i]-'0',nans%=(a==1?mod:phi);//细节1
	for(int i=0;i<lm;i++)
	mans=(mans<<3)+(mans<<1)+m[i]-'0',mans%=(c==1?mod:phi);

//	cout<<nans<<" "<<mans<<endl;
	
	A=qpow(A,mans-1);
//	cout<<A.a[1][1]<<endl;
	B=mul(B,A);//细节2
	B=qpow(B,nans-1);
	A=mul(A,B);
//	cout<<B.a[1][1]<<endl;
	ans=mul(Ans,A);
	printf("%lld\n",ans.a[1][1]);
	return 0;
}
### 细节一
有~~小定理说过~~ a^b与a^b%phi(p)在p意义下同余,phi这时就是p-1(p为素数)
对于a=1或c=1时 
此时特殊考虑
整个式子变为一次项且只与b和d有关
那就不如直径%p好了

### 细节二
矩阵乘法是没有交换律的
乘的时候注意行列顺序

标签:游戏,int,ll,矩阵,ans,mul,Matrix
来源: https://www.cnblogs.com/llwwll/p/16691461.html