[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[ egin{matrix} 1\ 1 end{matrix} ight] ]

列转移矩阵(A_1)

[A_1= left[ egin{matrix} a & b\ 0 & 1 end{matrix} ight] ]

行转移矩阵(A_2)

[A_2= left[ egin{matrix} c & d\ 0 & 1 end{matrix} ight] ]

转移到最后一行,最后一列,应该是

[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
",(A2[0][0]+A2[0][1])%mod);
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}
静渊以有谋,疏通而知事。
原文地址:https://www.cnblogs.com/autoint/p/9766727.html