矩阵游戏

描述

婷婷是个喜欢矩阵的小朋友,有一天她想用电脑生成一个巨大的n行m列的矩阵(你不用担心她如何存储)。她生成的这个矩阵满足一个神奇的性质:若用F[i][j]来表示矩阵中第i行第j列的元素,则F[i][j]满足下面的递推式:

 递推式中a,b,c,d都是给定的常数。
现在婷婷想知道F[n][m]的值是多少,请你帮助她。由于最终结果可能很大,你只需要输出F[n][m]除以1,000,000,007的余数。

输入

一行有六个整数n,m,a,b,c,d。意义如题所述。

1<=N,M<=10^1000 000,a<=a,b,c,d<=10^9

输出

包含一个整数,表示F[n][m]除以1,000,000,007的余数

样例输入

 3 4 1 3 2 6

样例输出

 85

提示

样例中的矩阵为:

1 4 7 10
26 29 32 35
76 79 82 85

显然使用矩阵快速幂

横向递推公式如下图

 纵向递推矩阵则把a,b替换成c,d

所以最终结果ans=初始矩阵*(横向转移矩阵)^(m-1)*(纵向转移矩阵*(横向转移矩阵)^(m-1))^(n-1)

因为n,m输入很大,所以快速幂用/2计算是不行的,直接使用十进制的快速幂

#include <bits/stdc++.h>
using namespace std;
#pragma GCC optimize(2)
string n,m,tf;
long long A,B,C,D;
const long long mod=1000000007;
inline void solve(long long x[2][2],long long y[2][2])//矩阵运算,结果覆盖x
{
long long t[2][2]={0,0,0,0};
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
for(int k=0;k<2;k++)
{
t[i][j]+=x[i][k]*y[k][j];
t[i][j]%=mod;
}
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
x[i][j]=t[i][j];
}
inline void dec(string s)//减一
{
s.back()--;
for(int i=s.length()-1;i>=0;i--)
{
if(s[i]<'0')
{
s[i]='9';
s[i-1]--;
}
else break;
}
tf=s;
}
signed main()
{
char x;
while(1)//快读n
{
x=getchar();
if(x==' ')break;
n+=x;
}
while(1)//快读m
{
x=getchar();
if(x==' ')break;
m+=x;
}
cin>>A>>B>>C>>D;
long long c[2][2]={A,0,B,1};//横向转移
long long r[2][2]={C,0,D,1};//纵向转移
long long f[2][2]={1,1,0,0};//初始矩阵
long long ans1[2][2]={1,0,0,1};//单位矩阵
dec(n),n=tf;//n=n-1
dec(m),m=tf;//m=m-1
for(int i=m.length()-1;i>=0;i--)//遍历m,用十进制快速幂计算矩阵
{
for(int k=1;k<=m[i]-'0';k++) solve(ans1,c);
long long tt[2][2]={1,0,0,1};
solve(tt,c);
solve(tt,c);
solve(c,c);
solve(c,c);
solve(c,c);
solve(c,tt);//底矩阵=底矩阵^10
}
solve(f,ans1);//更新答案
solve(r,ans1);//把一次纵向转移和m-1次横向转移结合
for(int i=n.length()-1;i>=0;i--)//遍历n
{
for(int k=1;k<=n[i]-'0';k++) solve(f,r);
long long tt[2][2]={1,0,0,1};
solve(tt,r);
solve(tt,r);
solve(r,r);
solve(r,r);
solve(r,r);
solve(r,tt);
}
cout<<f[0][0];
}

 

posted @ 2023-08-11 23:03  sleepaday  阅读(24)  评论(0编辑  收藏  举报