快速冪,矩陣快速冪原理介紹
阿新 • • 發佈:2018-12-24
快速冪:複雜度為logn,比普通的n快了很多了.
原理 :
以求a的b次方來介紹:
首先把b轉換成二進位制數
該二進位制數第i位的權為 2^i - 1 .
比如 : 11的二進位制是101111 = 2³×1 + 2²×0 + 2¹×1 + 2º×1
所以假設我們要求a^b,那麼其實b是可以拆成二進位制的,該二進位制數第i位的權為2^(i-1),例如當b==11時
a^11=a^(2^0+2^1+2^3)
實現程式碼如下:(位運算,簡單,簡潔)
ll pow(ll x, ll y) //位運算
{
ll res = 1;
while(y) {
if (y&1) res *= x ; //res才是最終我們要的結果.
x *= x ; //一箇中間轉移量. y每右移一次, x 就多一個平方.
y >>= 1 ;
}
return res;
}
矩陣快速冪:
思想和快速冪差不多,只是這裡是矩陣 , 而那個是數的差別.
所以原理和思想就不多說了 , 然後直接上程式碼
while(b)
{
if(b&1) res *= A; //res是結果矩陣.
A *= A; //和快速冪一樣,每一次都是乘一個平方,因為最多也是差2的幾次方的問題.
b >>= 1 ;
}
提供一個騷氣的寫法,就可以不用每一次寫矩陣形式,就是過載 * 號運算子. 程式碼如下:
#define Fill(x,y) memset(x,y,sizeof(x))
struct Ma{
int mat[30][30];
int n, m;
void cc() { Fill(mat, 0); }
void set_size(int row, int col) { n = row; m = col; }
Ma& operator = (const Ma &a ) {
set_size(a.n, a.m);
memcpy (mat, a.mat, sizeof(a.mat));
return *this;
}
friend Ma operator * (const Ma &a, const Ma &b) { // 語法規則.
Ma tmp; tmp.cc(); tmp.set_size(a.n, b.m);
for(int i = 1 ; i <= a.n ; i ++) {
for(int j = 1 ; j <= b.m ; j ++) {
for(int k = 1 ; k <= b.n ; k ++) { // a.m == b.n;
if(!a.mat[i][k] || !b.mat[k][j]) continue;
tmp.mat[i][j] += (a.mat[i][k] * b.mat[k][j]); //都把這個優化加
//上, 在有些卡數的題中會遇到.(如某個校賽F題)因為一些稀疏矩陣就可以通過這樣優化
//tmp.mat[i][j] %= mod;
}
}
}
return tmp;
}
void pfma() {
for (int i = 1 ; i <= n ; i ++) {
for (int j = 1 ; j <= m ; j ++) {
printf("%d%c", mat[i][j], j == m?'\n':' ');
}
}
}
}res,x; //有許多寫法,這只是其中一種,我認為好理解點的!
void solve()
{
res.set_size(1, 2);
res.mat[1][1] = 1; res.mat[1][2] = 2;
res.pfma();
x = res;
x.pfma();
x.set_size(2, 3);
x.mat[1][1] = 2; x.mat[1][2] = 4; x.mat[1][3] = 5;
x.mat[2][1] = 3; x.mat[2][2] = 7; x.mat[2][3] = 8;
x.pfma();
Ma tmp = res * x;
tmp.pfma();
}