九度OJ 1089 递推数列

本文介绍了一种使用矩阵快速幂方法求解特定形式线性递推数列第k项模10000的问题。通过矩阵运算优化传统方法的时间复杂度从O(n)降低至O(log n),并提供了详细的算法实现步骤及代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述:

给定a0,a1,以及an=p*a(n-1) + q*a(n-2)中的p,q。这里n >= 2。 求第k个数对10000的模。

输入:

输入包括5个整数:a0、a1、p、q、k。

输出:

第k个数a(k)对10000的模。

样例输入:
20 1 1 14 5

样例输出:

8359

本题用常规做法,时间复杂度为O(n),必定超时。用矩阵快速幂改进之后,时间复杂度提高到O(logn)

注意到本题的规律:


那么,求Ak,我们就可以用以下式子:


下面就是如何求矩阵[p q; 1 0]的(k-1)次幂。

矩阵快速幂的关键思想是利用二进制位来减少乘积的次数。

例如:A^(101010) = A^(100000) + A^(00000)+A^(1010)+A^(000)+A^(10)+A^(0)

什么意思呢,也就是说,求一个A的101010次方,我们可以转化成右边的式子,减少乘法的次数。

结合代码讲:

N表示幂,res表示要求的结果,初值为1,A表示底

while(N){
	if(N & 1){   
		res = res * A;    //表示该位值为1,就要把该位对应的数乘进来 
	} 
		N >>= 1;        //右移一位,即判断下一个高位 
		A = A * A;      //每次指针向前指一位,变成原来的平方 
}

分析:当指针指向末位的0,res的值不动,右移一位,基值Adouble一下,变为A^2;

下一次指针指向左边的1时,res = res * A^2,表示该位要乘进来,然后继续下去。也就是说,如果哪位是1,将该位对应的A^? 乘进来,就是这么回事。

本题中只要将A换成矩阵,数的运算,重新定义矩阵的乘法运算即可。还要注意前两个数是特例,不能带入递推式子。

#include <iostream>
#include <cstring>
#define mod 10000
using namespace std;

typedef long long ll;
ll a0,a1,p,q,k;

typedef struct Matrix{
	int num[2][2];
	void init(){
		memset(num,0,sizeof(num));
		for(int i=0;i<2;i++)
			num[i][i] = 1;
	}
}Matrix;

Matrix multi(Matrix X,Matrix Y){
	Matrix Result;
	Result.num[0][0] = Result.num[0][1] = Result.num[1][0] = Result.num[1][1] = 0;
	for(int i=0;i<2;i++){
		for(int j=0;j<2;j++){
			for(int k=0;k<2;k++){
				Result.num[i][j] += X.num[i][k]*Y.num[k][j];
			}
			Result.num[i][j] = Result.num[i][j] % mod;
		}
	}
	return Result;
}

void calculation(int N){
	Matrix A;
	A.num[0][0] = p;
	A.num[0][1] = q;
	A.num[1][0] = 1;
	A.num[1][1] = 0;
	Matrix res;
	res.init();
	while(N){
		if(N & 1)
			res = multi(res,A);
		N >>= 1;
		A = multi(A,A);
	}
	cout<<(res.num[0][0]*a1+res.num[0][1]*a0)%mod<<endl;
}

int main(){
	while(cin>>a0>>a1>>p>>q>>k){
		if(k == 0)
			cout<<a0%mod<<endl;
		else if(k == 1)
			cout<<a1%mod<<endl;
		else{
			calculation(k-1);
		}
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值