Explanation of fast power principle

Reprinted from: http://www.cnblogs.com/CXCXCXC/p/4641812.html

Reference: https://baike.baidu.com/item/quick power/5500243?fr=aladdin

The fast power is easy to understand, but it is easy to implement. I remember it a few times and always forget it. Today, I will summarize it systematically to prevent forgetting.

  First of all, the purpose of fast exponentiation is to achieve fast exponentiation. Suppose we require a^b. According to the naive algorithm, a is multiplied by b times, so that the time complexity is O(b), which is O(n) level. , the fast power can do O(logn), which is much faster. Its principle is as follows:

  Suppose we ask for a^b, then b can actually be split into binary, and the weight of the i-th bit of the binary number is 2^(i-1), for example, when b==11

                             a11=a(2^0+2^1+2^3)
  The binary of 11 is 1011, 11 = 2³×1 + 2²×0 + 2¹×1 + 2º×1, therefore, we convert a¹¹ into a 2^0 *a 2^1 *a 2^3 , which is a 1 *a 2 *a 8  , it seems that it is much faster. It used to count 11 times, but now it counts three times, but these three items seem to be difficult to ask for.... No hurry, there will be a detailed explanation below.                                                                                            
    Since it is binary, it is natural to think of using the powerful tool of bit operation: & and >>    
    The & operation is usually used for binary bit operations. For example, the result of a number & 1 is to take the last bit of the binary. It can also be judged that the parity x&1==0 is even, and x&1==1 is odd.
    >>The operation is relatively simple, the last bit is removed from the binary, not much to say, put the code first and then explain.


int poww(int a, int b) {
    int ans = 1, base = a;
    while (b != 0) {
        if (b & 1 != 0)
            ans *= base;
            base *= base;
            b >>= 1;
    }
    return ans;
}

 The code is very short, and memorization is also feasible, but it is better to understand it. In fact, it is also very easy to understand. Take b==11 as an example, b=>1011, the binary is counted from right to left, but the order of multiplication is a^ (2^0)*a^(2^1)*a^(2^3), from left to right. We keep making base*=base the purpose of multiplying, so as to contribute to ans at any time.

  It is necessary to understand the step of base*=base: because base*base==base 2 , the next multiplication is base 2 *base 2 ==base 4 , and then similarly base 4 *base 4 =base 8 , so you can Do base-->base 2 -->base 4 -->base 8 -->base 16 -->base 32 ....... The index is exactly 2^i, and look at the above example, a¹¹= a 1 *a 2 *a 8 , these three terms can be solved perfectly, and fast power is like this.

    By the way, since the exponential function is a function of explosive growth, it is very likely that the range of int will explode. It is up to you to choose long long or mod a certain number according to the meaning of the question.

  The same is true for the fast exponentiation of the matrix. Below is a matrix fast exponentiation template for finding the Fibonacci sequence.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int mod = 10000;
const int maxn = 35;
int N;
struct Matrix {
    int mat[maxn][maxn];
    int x, y;
    Matrix() {
        memset(mat, 0, sizeof(mat));
        for (int i = 1; i <= maxn - 5; i++) mat[i][i] = 1;
    }
};
inline void mat_mul(Matrix a, Matrix b, Matrix &c) {
    memset(c.mat, 0, sizeof(c.mat));
    c.x = a.x; c.y = b.y;
    for (int i = 1; i <= c.x; i++) {
        for (int j = 1; j <= c.y; j++) {
            for (int k = 1; k <= a.y; k++) {
                c.mat[i][j] += (a.mat[i][k] * b.mat[k][j]) % mod;
                c.mat[i][j] %= mod;
            }
        }
    }
    return ;
}
inline void mat_pow(Matrix &a, int z) {
    Matrix ans, base = a;
    ans.x = a.x; ans.y = a.y;
    while (z) {
        if (z & 1 == 1) mat_mul(ans, base, ans);
        mat_mul(base, base, base);
        z >>= 1;
    }
    a = ans;
}
int main() {
    while (cin >> N) {
        switch (N) {
            case -1: return 0;
            case 0: cout << "0" << endl; continue;
            case 1: cout << "1" << endl; continue;
            case 2: cout << "1" << endl; continue;
        }
        Matrix A, B;
        A.x = 2; A.y = 2;
        A.mat[1][1] = 1; A.mat[1][2] = 1;
        A.mat[2][1] = 1; A.mat[2][2] = 0;
        B.x = 2; B.y = 1;
        B.mat[1][1] = 1; B.mat[2][1] = 1;
        mat_pow(A, N - 1);
        mat_mul(A, B, B);
        cout << B.mat[1][1] << endl;
    }
    return 0;
}


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325684144&siteId=291194637