[NOI2013]矩阵游戏
题意
婷婷是个喜欢矩阵的小朋友,有一天她想用电脑生成一个巨大的n行m列的矩阵(你不用担心她如何存储)。她生成的这个矩阵满足一个神奇的性质:若用F[i][j]来表示矩阵中第i行第j列的元素,则F[i][j]满足下面的递推式:
F[1][1]=1
F[i,j]=a*F[i][j-1]+b (j!=1)
F[i,1]=c*F[i-1][m]+d (i!=1)
递推式中a,b,c,d都是给定的常数。
现在婷婷想知道F[n][m]的值是多少,请你帮助她。由于最终结果可能很大,你只需要输出F[n][m]除以1,000,000,007的余数。
分析
初始矩阵\(A_3\)
\[A_3=
\left[
\begin{matrix}
1\\
1
\end{matrix}
\right]
\]
列转移矩阵\(A_1\)
\[A_1=
\left[
\begin{matrix}
a & b\\
0 & 1
\end{matrix}
\right]
\]
行转移矩阵\(A_2\)
\[A_2=
\left[
\begin{matrix}
c & d\\
0 & 1
\end{matrix}
\right]
\]
转移到最后一行,最后一列,应该是
\[A_1^{m-1}(A_2A_1^{m-1})^{n-1}A_3
\]
代码
n,m是十进制大数,需要十进制快速幂。
此题还有数学分析做法,矩阵的做法卡常数,需要O3才能过
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<ctime>
#include<iostream>
#include<string>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<complex>
#define il inline
#define rg register
#pragma GCC optimize ("O3")
using namespace std;
template<class T> inline T read(T&x)
{
T data=0;
int w=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
w=-1;
ch=getchar();
}
while(isdigit(ch))
data=10*data+ch-'0',ch=getchar();
return x=data*w;
}
typedef long long ll;
const int INF=0x7fffffff;
const int mod=1e9+7;
struct Matrix
{
int data[2][2];
il Matrix()
{
memset(data,0,sizeof(data));
}
il int*operator[](rg const int&x)
{
return data[x];
}
il Matrix operator*(rg const Matrix&rhs)
{
rg Matrix res;
for(rg int i=0;i<2;++i)
for(rg int j=0;j<2;++j)
for(rg int k=0;k<2;++k)
{
res[i][j] += (ll)data[i][k] * rhs.data[k][j] % mod;
if(res[i][j] >= mod)
res[i][j] -= mod;
}
return res;
}
il Matrix&operator*=(rg const Matrix&rhs)
{
return *this=*this*rhs;
}
}A1,A2,A3;
il Matrix spow(rg Matrix x,rg int k)
{
rg Matrix res;
for(rg int i=0;i<2;++i)
res[i][i]=1;
while(k)
{
if(k&1)
res*=x;
x*=x,k>>=1;
}
return res;
}
il Matrix bpow(rg Matrix x,rg char*k)
{
rg Matrix res;
for(rg int i=0;i<2;++i)
res[i][i]=1;
rg int len=strlen(k+1);
for(rg int i=len;i;--i)
{
res *= spow(x,k[i]-'0');
x = spow(x,10);
}
return res;
}
const int MAXN=1e6+7;
char n[MAXN],m[MAXN];
int a,b,c,d;
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
scanf("%s %s",n+1,m+1);
read(a);read(b);read(c);read(d);
int nl=strlen(n+1),ml=strlen(m+1);
for(rg int i=nl;i;--i)
{
if(n[i]=='0')
n[i]='9';
else
{
n[i]--;
break;
}
}
for(rg int i=ml;i;--i)
{
if(m[i]=='0')
m[i]='9';
else
{
m[i]--;
break;
}
}
A1[0][0]=a,A1[0][1]=b,A1[1][1]=1;
A1=bpow(A1,m);
A2[0][0]=c,A2[0][1]=d,A2[1][1]=1;
A2*=A1,A2=A1*bpow(A2,n);
printf("%d\n",(A2[0][0]+A2[0][1])%mod);
// fclose(stdin);
// fclose(stdout);
return 0;
}
静渊以有谋,疏通而知事。