矩阵游戏
作者:互联网
矩阵游戏
是一道氵题;
正好拿来练矩阵乘法;
题目传送门 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