前几日笔者在打训练赛时,见到了这样一道题,这是华中科技大学新生赛的一道题目
可以通过数学知识简单的分析出其递推关系
笔者写时得到了这个关系,但是这样递推后却超时了,因为这道题数据很大,为十的十八次方
后来看题解,题解这么说
笔者当时不知道矩阵快速幂为何物,后来查阅资料后明白了,先说一下快速幂
当指数很小时,我们可以通过循环轻易求出一个数的幂,但是当指数大于一亿后,就会超时。
所以我们引入快速幂的思想,每将底数扩大一倍,指数就会小二分之一,以此类推,快速幂的时间复杂度为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;
}
那为什么这道题用普通快速幂不行呢,因为这道题的递推不是简单的乘一个数,我们可以用矩阵写出
我们只需把快速幂中的底数换成矩阵即可
代码如下
#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阶矩阵快速幂的模版,如有不当之处,请大家多多指正