一.主要功能
–>快速幂算法能帮我们算出指数非常大的幂,传统的求幂算法之所以时间复杂度非常高,就是因为当指数n非常大的时候,需要执行的循环操作次数也非常大。所以快速幂算法的核心思想就是每一步都把指数分成两半,而相应的底数做平方运算。这样不仅能把非常大的指数给不断变小,所需要执行的循环次数也变小。
二.关于取余的重要性质
1.指数较大时题中通常会有一个取余运算,而取余主要包括以下三个性质
1).(a + b) % p = (a % p + b % p) % p
2).(a - b) % p = (a % p - b % p ) % p
3).(a * b) % p = (a % p * b % p) % p
2.也就是在中间运算过程中就可以同时做取余运算,防止最后的数值过大。
三、经典例题
Question:HDU1575求矩阵的迹
1. 矩阵快速幂
–>只需记录当指数为奇数时的底数值即可。
Matrix fastPower(Matrix base, int power, int modulus) //矩阵快速幂运算
{
Matrix result(1);
result.n = base.n;
while (power > 0)
{
if (power % 2 == 0)
{
power /= 2;
base = base * base;
}
else
{
power -= 1;
result = result * base;
power /= 2;
base = base * base;
}
}
return result;
}
2.关于快速幂部分还可以使用位运算优化
Matrix fastPower(Matrix base, int power, int modulus) //矩阵快速幂运算
{
Matrix result(1);
result.n = base.n;
while (power)
{
if (power & 1) //与1相与可以判断是否为奇数
result = result * base;
power >>= 1;
base = base * base;
}
return result;
}
3.完整代码展示:
#include <iostream>
#include <stdio.h>
using namespace std;
const int MaxSize = 12;
class Matrix{
public:
int data[MaxSize][MaxSize];
int n;
public:
Matrix()
{
n = 0;
for (int i = 0; i < MaxSize; ++ i)
for (int j = 0; j < MaxSize; ++ j)
data[i][j] = 0;
}
Matrix (int initial) //注意在创建单位矩阵的时候不要只管data[i][i] = 1;还需要剩下的位置赋0值。自己评测的时候因为这个查了 很久!!!
{
n = 0;
for (int i = 0; i < MaxSize; ++ i)
for (int j = 0; j < MaxSize; ++ j)
{
if (i == j) data[i][j] = 1;
else data[i][j] = 0;
}
}
Matrix (const Matrix& tmp)
{
n = tmp.n;
for (int i = 0; i < n; ++ i)
for (int j = 0; j < n; ++ j)
data[i][j] = tmp.data[i][j];
}
Matrix operator *(const Matrix& tmp)
{
Matrix result;
int Mod = 9973;
result.n = n;
for (int i = 0; i < n; ++ i)
for (int j = 0; j < n; ++ j)
{
for (int k = 0; k < n; ++ k)
result.data[i][j] = (result.data[i][j] + data[i][k] * tmp.data[k][j] % Mod) % Mod;
result.data[i][j] %= Mod;
}
return result;
}
Matrix operator %(const int modulus)
{
Matrix result;
result.n = n;
for (int i = 0; i < n; ++ i)
for (int j = 0; j < n; ++ j)
result.data[i][j] = data[i][j] % modulus;
return result;
}
Matrix& operator =(const Matrix& tmp) //小细节:此处返回类型应该为引用,方便连续赋值。
{
n = tmp.n;
for (int i = 0; i < n; ++ i)
for (int j = 0; j < n; ++ j)
data[i][j] = tmp.data[i][j];
return *this;
}
}; // 重载各类运算符
Matrix fastPower(Matrix base, int power, int modulus) //矩阵快速幂运算
{
Matrix result(1);
result.n = base.n;
while (power > 0)
{
if (power % 2 == 0)
{
power /= 2;
base = base * base;
}
else
{
power -= 1;
result = result * base;
power /= 2;
base = base * base;
}
}
return result;
}
void caltrace(Matrix& tmp, int n, int modulus) //求矩阵的迹
{
int ans = 0;
for (int i = 0; i < n; ++ i)
ans = (ans + tmp.data[i][i]) % modulus;
cout << ans % modulus << endl;
return;
}
int main()
{
freopen("in.txt", "r", stdin);
int n, k;
cin >> n >> k;
Matrix m;
for (int i = 0; i < n; ++ i)
for (int j = 0; j < n; ++ j)
cin >> m.data[i][j];
m.n = n;
Matrix seq = fastPower(m, k, 9973);
caltrace(seq, n, 9973);
return 0;
}