快速冪 矩陣快速冪

2021-08-08 14:16:06 字數 3283 閱讀 1537

快速冪

正常情況下求乙個數的冪時間複雜度為o(n),而快速冪能把時間複雜度降到o(logn)。

舉個例子:求5的13次方

思想首先把13化為二進位制:1101,即13 = 1101 = 8 * 1 + 4 * 1 + 2 * 0 + 1 * 1 。

即5 13=

58∗1

+54∗

1+52

∗0+5

1∗

15^ = 5^8 * 1 + 5^4 *1 +5 ^ 2 * 0 + 5^1 * 1

513=58

∗1+5

4∗1+

52∗0

+51∗

1 1,

52,5

4,58

5^1,5^2,5^4,5^8

51,52,

54,5

8這四個數,這四個數有乙個很明顯的規律,後乙個數等於前乙個數的平方。

如果我知道第乙個數51=

55^1 = 5

51=5

,那很輕鬆就能求出第二個數是5 * 5 = 25,

接著,第三個數 25 * 25 = 625,

第四個數 625 * 625 = 390625

如果後邊還有更多,可以接著往下求。

上述過程用乙個迴圈就能解決:

long long ans = 1

long long x = 5

long long n = 4

while(n)

迴圈結束之後,ans的值就是5 * 25 * 625 * 390625的值,也就是51∗

52∗5

4∗58

5^1 * 5^2 * 5^4 * 5^8

51∗52∗

54∗5

8的值。

現在再看如果把1101 加上該怎麼算。

可以發現1對結果沒有任何影響:51∗

1和51

5^1 * 1 和 5^1

51∗1和5

1沒有區別。

再看0產生的影響:52∗

0=50

=1

5^2 * 0 = 5^0 = 1

52∗0=5

0=1,即如果是0,會把該項變成1。

那要對上面的**稍作更改,就可以求帶1101的式子的積:

long long ans = 1

long long x = 5

long long n = 4

long long arr = [1, 0, 1, 1]

int i = 0

while(n)

i++;

x *=x;

n--;

}

這樣計算出來的就是58∗

1∗54

∗1∗5

2∗0∗

51∗1

=5

135^8 * 1 * 5^4 * 1 * 5^2 * 0 * 5^1 * 1 = 5^

58∗1∗5

4∗1∗

52∗0

∗51∗

1=51

3的值。

以上就是快速冪的思想:把指數化成二進位制,然後根據這個二進數每一位上是0還是1來判斷進行什麼操作。

但是上面的**顯然是沒法使用的,因為我們所有的變數都是寫死的,那接下來就來看看怎麼把思想變成**。

**實現

整個快速冪一共要做的就是兩件事:

1.把指數化成二進位制形式。

2.根據這個二進數每一位上是0還是1來判斷進行什麼操作。

乙個很容易想到的方法是把兩步分開,先化二進位制,然後把二進位制存成陣列或者字串形式,再來判斷。

#include#include#include#include#define ll long long

const int mod=1e7+7;

using namespace std;

int arr[50];//儲存指數轉化後的二進位制

int cnt = 1;

ll ans = 1;//儲存最終結果

void get_binary(ll n)//轉化成二進位制

}ll get_ans(ll x)

x *= x;

cnt--;

}return ans;

}int main()

cout << endl;

cout << get_ans(x) << endl;

}//以5 13輸入為例

//上邊的**第35行輸出的是 1 0 1 1(可以發現是反著儲存的(13化二進位制是1101),所以求結果的時候也要反著來)

//然後38行輸出 1220703125

上邊的方法自然是可行的,時間複雜度也是兩次log2n的迴圈。

不過還是可以小小的優化一下。

其實完全沒必要把二進位制結果存下來,因為這個東西只用到了一次,而且用二進位制的每一位的時候和它前後都無關,所以我們完全可以在求二進位制每一位的時候同時進行結果的運算。

#include#include#include#include#define ll long long

const int mod=1e7+7;

using namespace std;

ll ans = 1;//儲存最終結果

ll get_binary(ll x, ll n)//轉化成二進位制

x *= x;

n /= 2;

}return ans;

}int main()

上面就幾乎是標準的快速冪寫法了。接下來還有兩個小地方補充:

第十二行的n % 2 可以換成 n & 1 ,兩者是可以劃等號的。同樣,第十六行的n /= 2也可以換成 n >>= 1,這個操作是把二進位制右移一位,也就相當於除以2。之說以這樣寫據說是計算機中進行二進位制運算比十進位制要快那麼一丟丟。

求快速冪一般都會伴隨著取餘,否則根本存不下。上面的**如果改的話只需要把第13和15行改一下就可以了:

while(n > 0)

x = (x * x) % mod;

n /= 2;

}

之所以可以這樣寫是因為取模的法則:

(a + b) % p = (a % p + b % p) % p

(a - b) % p = (a % p - b % p ) % p

(a * b) % p = (a % p * b % p) % p

矩陣快速冪

快速冪(矩陣快速冪)

求 3 0 3 1 3 n mod 1000000007 input 輸入乙個數n 0 n 10 9 output 輸出 計算結果 sample input 3sample output 40 分析 利用等比數列的求和公式得所求和是 3 n 1 1 2,如果暴力求3 n 1 會超時,這裡引入快速冪來...

快速冪 矩陣快速冪

快速冪 我們求a ba b ab最直接的方法就是把a乘b次這樣的話複雜度就是o n o n o n 但是在比賽時面對1e9的資料時還是會輕鬆超時的,此時就需要一種更快的乘法來幫助我們 我們把b拆成二進位制的形式得到a ba b ab a 10.01 a a1 0.01此時對b分解得到的序列10.01...

快速冪 矩陣快速冪

如果要你自己寫乙個pow 函式,需要求2的2000000000次方,怎麼求?int pow int a,int b 上述 的時間複雜度是o n 當資料數量級很大的時候,這份 的耗時會非常巨大,並不能解決我們的問題。那我們該怎麼辦呢?以2的74次方為例,74的二進位制為1001010。對應的,我們得到...