[NOI2013]矩阵游戏(矩阵乘法+十进制快速幂)

题目大意:

一个n行m列的矩阵,

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)

其中:1<=n,m<=10^1000000,1<=a,b,c,d<=10^9

输出F[n][m]除以1,000,000,007的余数


如果用快速幂的话,需要把十进制数n,m转化为二进制,而n,m要用字符串来存储且极大,所以会TLE

这里使用十进制快速幂

另外,构造的矩阵只能用到第一列,因此把它们化简到两个元素即可,可以减小时间常数


具体见代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define mod 1000000007
typedef long long LL;
char sn[1000005],sm[1000005];
struct juzhen
{
	LL v1,v2;//矩阵化简:对于s[1][2]==0的矩阵,只保留s[1][1],s[2][1];不需要Z矩阵 
};
juzhen I;//单位矩阵 
juzhen cheng(juzhen a,juzhen b)
{
	juzhen res;
	res.v1=(a.v1*b.v1)%mod;
	res.v2=(a.v2*b.v1+b.v2)%mod;
	return res;
}
juzhen ksm(juzhen a,int n)
{
	juzhen res;
	if(n==0) return I;
	if(n==1) return a;
	res=ksm(a,n/2);
	res=cheng(res,res);
	if(n%2==1) res=cheng(res,a);
	return res;
}
juzhen T_ksm(juzhen a,char s[],int len)//十进制快速幂:O(10*lg(n)) 
{
	juzhen res=I,t=a;
	for(;len>=0;len--)
	{
		res=cheng(res,ksm(t,s[len]-'0'));
		t=ksm(t,10);
	}
	return res;
}
int main()
{
	juzhen A,B,C;
	int i,Ln,Lm;
	scanf("%s%s",sn,sm);
	Ln=strlen(sn)-1;
	sn[Ln]--;//n--
	for(i=Ln;sn[i]<'0';i--)
	{
		sn[i]+=10;
		sn[i-1]--;
	}
	Lm=strlen(sm)-1;
	sm[Lm]--;//m--
	for(i=Lm;sm[i]<'0';i--)
	{
		sm[i]+=10;
		sm[i-1]--;
	}
	scanf("%lld%lld%lld%lld",&A.v1,&A.v2,&B.v1,&B.v2);
	I.v1=1;
	I.v2=0;
	A=T_ksm(A,sm,Lm);
	C=cheng(B,A);
	C=T_ksm(C,sn,Ln);
	C=cheng(A,C);
	printf("%lld",(C.v1+C.v2)%mod);
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值