快速冪的理解及使用
阿新 • • 發佈:2022-01-08
快速冪
1.快速冪定義
快速冪也稱為平方求冪(exponentiating by squaring)
快速冪時計算一個數的大正整數乘冪的一般方法(對多項式,矩陣也適用)
\[x^n = \begin{cases} x(x^2)^{\frac{n-1}{2}}, & \text {if $n$ is odd}\\ (x^2)^{\frac{n}{2}}, & \text {if $n$ is even} \end{cases} \]平方法轉換思想:
將指數的位,二進位制的位,來確定計算哪些冪
\[x = a * b ^n , x= a * (b^2)^{\frac{n}{2}} \]每次把b進行平方,將n看作一個二進位制的數,如果k位為1,則最後的結果需要乘上 b(2
b= 13(1101)
\[x = b^{13} , = b^1 * b^{4} * b^8 \]程式碼實現:
# a * b^n
def quickPower(a,b,n):
x = a
p = b
while n >0:
if(n & 1) == 1:
x = x * p
p = p * p # p,p^2,p^4,p^8
n = n >> 1
return x
- 上述對矩陣同樣適用
- 由於冪函式求解,數值會比較大,通常在每一步計算的時候都會進行取餘操作
// b^n int MOD = 10e9; long long power(long long p,long long n){ long long ans = 1; while(n > 0){ if (n & 1 == 1) ans = (ans * p) % MOD; p = p * p % MOD; n >>=1; } }
2.快速冪應用
計算大指數冪除以一個數的餘數,在密碼學中應用較多
// a^b % MOD // b是以一個大數,儲存在陣列中 class Solution { private int MOD = 1337; public int superPow(int a, int[] b) { return dfs(a,b,b.length -1); } private int dfs(int a,int[] b,int len){ if(len == -1) return 1; return quickPow(dfs(a,b,len-1),10) * quickPow(a,b[len]) % MOD; } private int quickPow(int a ,int b){ int ans = 1; a %= MOD; while(b > 0){ if( b & 1) ans = ans * a % MOD; a = a * a % MOD; b = b >> 1; } return ans; } }
快速冪在動態規劃中的應用
動態規劃主要用來解決兩種問題:
- 1.優化問題
- 2.組合計數問題
快速冪可以在組合計數問題中,對計算進行加速(時間複雜度從 O(n) -> O(logn))
[LeetCode.1411]
\[dp[i][0] = dp[i-1][0] * 3 + dp[i-1][1] * 2 , dp[i][1] = dp[i-1][0] * 2 + dp[i-1][1] * 2 \]邊界條件
\[dp[1][0] = dp[1][0] = 6 \] int numOfWays(int n) {
constexpr int MOD = 1e9 + 7;
vector<vector<long>> dp(n+1,vector<long>(2,6));
for(int i = 2;i<=n;i++){
dp[i][0] = (dp[i-1][0] * 3 + dp[i-1][1] *2) % MOD;
dp[i][1] = (dp[i-1][0] * 2 + dp[i-1][1] *2) % MOD;
}
return (dp[n][0] + dp[n][1]) % MOD;
}
轉換為矩陣求解
\[(dp[i][0],dp[i][1]) = (dp[i-1][0] ,dp[i-1][1]) * \begin{matrix} 3&2\\ 2&2\\ \end{matrix} , (dp[n][0], dp[n][1] = (dp[1][0] , dp[1][1])* \begin{matrix} 3&2\\ 2&2\\ \end{matrix} ^{n-1} \]class Solution {
public:
int numOfWays(int n) {
constexpr long kMod = 1e9 + 7;
vector<vector<long>> ans{{6, 6}}; // 1x2
vector<vector<long>> M{{3, 2},{2,2}}; // 2x2
auto mul = [kMod](const vector<vector<long>>& A,
const vector<vector<long>>& B) {
const int m = A.size(); // m * n
const int n = B.size(); // n * p
const int p = B[0].size();
vector<vector<long>> C(m, vector<long>(p));
for (int i = 0; i < m; ++i)
for (int j = 0; j < p; ++j)
for (int k = 0; k < n; ++k)
C[i][j] += (A[i][k] * B[k][j]) % kMod;
return C;
};
--n;
while (n) {
if (n & 1) ans = mul(ans, M); // ans = ans * M;
M = mul(M, M); // M = M^2
n >>= 1;
}
// ans = ans0 * M^(n-1)
return (ans[0][0] + ans[0][1]) % kMod;
}
};
不要用狹隘的眼光看待不瞭解的事物,自己沒有涉及到的領域不要急於否定.
每天學習一點,努力過好平凡的生活.