简易二阶矩阵快速幂(不取余)模版

前几日笔者在打训练赛时,见到了这样一道题,这是华中科技大学新生赛的一道题目

可以通过数学知识简单的分析出其递推关系

笔者写时得到了这个关系,但是这样递推后却超时了,因为这道题数据很大,为十的十八次方

后来看题解,题解这么说

笔者当时不知道矩阵快速幂为何物,后来查阅资料后明白了,先说一下快速幂

当指数很小时,我们可以通过循环轻易求出一个数的幂,但是当指数大于一亿后,就会超时。

所以我们引入快速幂的思想,每将底数扩大一倍,指数就会小二分之一,以此类推,快速幂的时间复杂度为O(log2 n),这要比循环的O(n)快多了。

代码如下(取余版)

#include <iostream>
#define int long long 
using namespace std;
int quick_power(int base, int power,int M)
{
	int result = 1;//记录结果
	while (power > 0)
	{
		if (power &1 )
		{
			result =result*base%M;//如果是奇数只乘一个
		}
		power >>= 1;
		base = base * base % M;//底数平方
	}
	int q = result % M;
	return q;
}


signed main()
{
	int a, b, M;
	cin >> a >> b >> M;
	int d = quick_power(a,b,M);
	cout << d;
	return 0;
}

那为什么这道题用普通快速幂不行呢,因为这道题的递推不是简单的乘一个数,我们可以用矩阵写出

\binom{f(n)}{f(n-1)}=\bigl(\begin{smallmatrix}k &-1 \\ 1 & 0 \end{smallmatrix}\bigr)*\binom{f(n-1)}{f(n-2)}

我们只需把快速幂中的底数换成矩阵即可

代码如下

#include <bits/stdc++.h>
using namespace std;

int a[2][2];
int b[2][2];

void marmul(void)//矩阵乘法
{
	int a11 = a[0][0], a12 = a[0][1], a21 = a[1][0], a22 = a[1][1];
	a[0][0] = b[0][0] * a11 + b[0][1] * a21;
	a[0][1] = b[0][0] * a12 + b[0][1] * a22;
	a[1][0] = b[1][0] * a11 + b[1][1] * a21;
	a[1][1] = b[1][0] * a12 + b[1][1] * a22;
	return;
}
void power(void)//底矩阵平方函数
{
	int b11 = b[0][0], b12 = b[0][1], b21 = b[1][0], b22 = b[1][1];
	b[0][0] = b11 * b11 + b12 * b21;
	b[0][1] = b11 * b12 + b12 * b22;
	b[1][0] = b21 * b11 + b22 * b21;
	b[1][1] = b21 * b12 + b22 * b22;
	return;
}
void quick_power(int n)//快速幂
{
	while (n> 0)
	{
		if (n & 1)
		{
			marmul();
		}
		n >>= 1;
		power();
	}
	return;
}
int main()
{
	int n;
	cin >> n;
	cin >> b[0][0];
	cin >> b[0][1];
	cin >> b[1][0];
	cin >> b[1][1];
	a[0][0] = a[1][1] = 1;
	a[0][1] = a[1][0] = 0;//单位阵记录结果
	quick_power(n);
	cout << a[0][0] << " " << a[0][1] << endl;
	cout << a[1][0] << " " << a[1][1] << endl;
	return 0;
}

之后笔者会推出n阶矩阵快速幂的模版,如有不当之处,请大家多多指正

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值