WEEK14 周记 作业——矩阵快速幂_必做题3-Q老师的考验

本文介绍如何使用矩阵快速幂解决特定线性递推数列问题,以求得f(k)%m的值,避免传统线性求解在大规模数据下超时的问题。文章详细解释了矩阵快速幂原理,并提供了完整的代码实现。

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

一、题意

1.简述

Q老师 对数列有一种非同一般的热爱,尤其是优美的斐波那契数列。

这一天,Q老师 为了增强大家对于斐波那契数列的理解,决定在斐波那契的基础上创建一个新的数列 f(x) 来考一考大家。数列 f(x) 定义如下:

当 x < 10 时,f(x) = x;
当 x ≥ 10 时,f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + …… + a9 * f(x-10),ai 只能为 0 或 1。

Q老师 将给定 a0~a9,以及两个正整数 k m,询问 f(k) % m 的数值大小。

聪明的你能通过 Q老师 的考验吗?

2.输入格式

输出文件包含多组测试用例,每组测试用例格式如下:

第一行给定两个正整数 k m。(k < 2e9, m < 1e5)

第二行给定十个整数,分别表示 a0~a9。

3.输出格式

对于每一组测试用例输出一行,表示 f(k) % m 的数值大小。

4.样例

Input

10 9999
1 1 1 1 1 1 1 1 1 1
20 500
1 0 1 0 1 0 1 0 1 0

Output

45
104

二、算法

主要思路

什么是矩阵快速幂?

考虑如下情景:给定矩阵 AAA,请快速计算出AnA^nAnnnn 个矩阵 AAA 相乘)的结果,输出的每个数都 %p\%p%p
矩阵快速幂类似于一般的快速幂。只不过我们需要为矩阵类重载乘号,然后直接调用前面学过的整数的快速幂的函数即可。
在这里插入图片描述


这个题为什么能用矩阵快速幂?

因为该题有矩阵的连乘。
我们再根据线性递推式(比如该题中的f(x)=a0∗f(x−1)+a1∗f(x−2)+a2∗f(x−3)+……+a9∗f(x−10)f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + …… + a9 * f(x-10)f(x)=a0f(x1)+a1f(x2)+a2f(x3)++a9f(x10))求解某一个值(比如f(k)f(k)f(k))时,如果直接按照线性递推式线性求解,遍历每一个点,那么必然会超时,因为该题的k<2e9k \lt 2e9k<2e9
但是我们可以将线性递推式的一步步推导转化为有规律的矩阵的连乘。对于该题,当k≥10k\ge10k10时,
[f(x)f(x−1)...f(x−9)]=[a0a1...a910...001...0............00...1]⋅[f(x−1)f(x−2)...f(x−10)] \begin{bmatrix} f(x) \\ f(x-1) \\ ... \\ f(x-9)\\ \end{bmatrix} = \begin{bmatrix} a_0& a_1 & ... & a_9 \\ 1 & 0 & ... & 0 \\ 0 & 1 & ... & 0\\ ... &...&...&...\\ 0 & 0 &...& 1 \\ \end{bmatrix} \cdot \begin{bmatrix} f(x-1) \\ f(x-2) \\ ... \\ f(x-10)\\ \end{bmatrix} f(x)f(x1)...f(x9)=a010...0a101...0...............a900...1f(x1)f(x2)...f(x10)一直推导可以推导出:[f(x)f(x−1)...f(x−9)]=[a0a1...a910...001...0............00...1]x−9⋅[f(9)f(8)...f(0)] \begin{bmatrix} f(x) \\ f(x-1) \\ ... \\ f(x-9)\\ \end{bmatrix} = {\begin{bmatrix} a_0& a_1 & ... & a_9 \\ 1 & 0 & ... & 0 \\ 0 & 1 & ... & 0\\ ... &...&...&...\\ 0 & 0 &...& 1 \\ \end{bmatrix}}^{x-9} \cdot \begin{bmatrix} f(9) \\ f(8) \\ ... \\ f(0)\\ \end{bmatrix} f(x)f(x1)...f(x9)=a010...0a101...0...............a900...1x9f(9)f(8)...f(0)
然后就可以利用矩阵快速幂了。

快速幂能将时间复杂度从O(n)O(n)O(n)降到O(logn)O(logn)O(logn)


三、代码

#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
int a[10];
const int N = 10;
int k,m;
struct Matrix{
	int x[N+1][N+1];
	Matrix operator*(const Matrix& r)const{
		Matrix rtn;
		for(int i=1;i<=N;i++){
			for(int j=1;j<=N;j++){
				rtn.x[i][j] = 0;
				for(int k=1;k<=N;k++){
					rtn.x[i][j] += (x[i][k]*r.x[k][j])%m;
					rtn.x[i][j] %= m;//这行必须加,因为rtn.x[i][j]有可能在累加的过程中超过m 
				}
			}
		}
		return rtn;
	}
};
Matrix quick_pow(Matrix a,int x){
	Matrix rtn;
	for(int i=1;i<=N;i++)
		for(int j=1;j<=N;j++)
			rtn.x[i][j] = i==j?1:0;
	
	while(x){
		if(x&1) rtn = rtn*a;
		a = a*a;
		x >>= 1;
	}
	return rtn;
}
int main(){
	while(scanf("%d%d",&k,&m)!=EOF){
		for(int i=0;i<10;i++) scanf("%d",&a[i]);
		Matrix ans;
		for(int i=1;i<=N;i++) ans.x[1][i] = a[i-1];
		for(int i=2;i<=N;i++){
			for(int j=1;j<=N;j++){
				ans.x[i][j] = i==j+1?1:0;
			}
		}
		if(k<10) printf("%d\n",k);
		else{
			int num = 0;
			ans = quick_pow(ans,k-9);
			for(int i=1;i<=N;i++){
				num += (ans.x[1][i]*(10-i))%m;
				num %= m;
			}
			printf("%d\n",num);
		}	
	}
	return 0;
} 
/*

*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值