一、爲什莫叫快速冪?矩陣快速冪又是什麼?
快速冪,是根據冪的二進制最後一位0或1來加速進行乘法運算。
例如,在求5^19時,按照普通的求法就是要19個5相乘,這樣雖然可以解出來,但當底數和指數都非常大時,這樣計算的時間會很長,其時間複雜度爲O(n)。但使用快速冪就要快速很多。其計算原理如下(下面底數用a表示,指數用n表示,下面的tmp初始爲a,ans初始爲1):
n=19的二進制是10011,
此時n爲奇數,則ans=ans*tmp;tmp=tmp*tmp;n右移一位;(ans=1*5,tmp=5*5=25)
此時n爲奇數,則ans=ans*tmp;tmp=tmp*tmp;n右移一位;(ans=5*25,tmp=25*25)
此時n爲偶數,則直接tmp=tmp*tmp;n右移一位;(ans=125,tmp=625*625)
此時n爲偶數,則直接tmp=tmp*tmp;n右移一位;(ans=125,tmp=390625*390625)
此時n爲奇數,則ans=ans*tmp;tmp=tmp*tmp;n右移一位;(ans=125*390625*390625,tmp=(390625*390625)^2);
這樣就已經求解成功,僅僅用了5次,大大節省了時間。其時間複雜度爲O(logn)。
矩陣快速冪,顧名思義,就是矩陣做冪運算。其實際和快速冪差不多,只是需要對矩陣的乘法運算去做*運算符的重載。其中有一個重要的矩陣就是單位矩陣,他就相當於數字1一樣,只是它是一個矩陣。例如2x2的單位矩陣爲:
a【0】【0】=1;a【0】【1】=0;
a【1】【0】=0;a【1】【1】=1;
二、快速冪模板
#include<iostream>
using namespace std;
typedef long long ll;
const ll MOD=1000007;
ll quickPow(ll a,ll n){ //求a^n
ll tmp=a;
ll ans=1;
while(n){
if(n&1){
ans=ans*tmp;
}
tmp=tmp*tmp;
n>>=1;
}
return ans;
}
int main(){
//功能需求
//............
return 0;
}
三、矩陣快速冪模板
#include<iostream>
#include<string.h>
using namespace std;
typedef long long ll;
const int Mod=100000007;
struct maxtri{
ll v[2][2];
maxtri (){
memset(v,0,sizeof(v)); //初始化矩陣
}
maxtri operator *(const maxtri &m){ //重載*運算符
maxtri tmp;
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
for(int k=0;k<2;k++){
tmp.v[i][j]+=(v[i][k]*m.v[k][j])%Mod;
}
}
}
return tmp;
}
};
maxtri M,E,ans; //M即爲矩陣,E即爲單位矩陣,ans爲解
void Init(){
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
if(i==j){
E.v[i][j]=1;
}
}
}
M.v[0][0]=2;M.v[0][1]=1; //具體情況具體值的初始化,這裏是舉例
M.v[1][0]=1;M.v[1][1]=0;
}
maxtri quickPow(maxtri m,ll n){ //核心代碼
maxtri tmp=E;
while(n){
if(n&1){
tmp=tmp*m;
}
m=m*m;
n>>=1;
}
return tmp;
}
int main(){
//功能需求
//............
return 0;
}
四、快速冪及矩陣快速冪的應用
1、快速冪
主要是求指數冪
2、矩陣快速冪
a.矩陣相乘;
b.求菲波那切數列的第n項(就是可以從前兩個狀態推到當前狀態,這個關係矩陣的係數還是比較好找的);
c.圖論中求對應兩個點長度爲n的路徑數,這是矩陣乘法在圖論中的經典應用,其實就是用到了矩陣乘法的特殊性,因爲矩陣乘法有三重循環,最裏面的一層循環就是在枚舉一個點k,i -> k -> j,那麼從i -> j的路徑數長度爲m的條數就等於i-> k路徑長度爲n的路徑數乘上k -> j路徑長度爲m - n的的路徑條數,枚舉的過程中全加起來,可以看到,這個過程和矩陣乘法的過程是一樣的。矩陣An中的ai,j表示:圖中點i到點j經過n條邊的路徑數。(只要能用矩陣乘法做的事情,一般都要用矩陣快速冪來假設)