1. 程式人生 > >快速冪,矩陣快速冪原理介紹

快速冪,矩陣快速冪原理介紹

快速冪:複雜度為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(); }