快速幂的使用

快速幂

1.快速幂定义

wiki

快速幂也称为平方求幂(exponentiating by squaring)

快速幂时计算一个数的大正整数乘幂的一般方法(对多项式,矩阵也适用)

x n = { x ( x 2 ) n − 1 2 , if  n  is odd ( x 2 ) n 2 , if  n  is even 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} xn={x(x2)2n1,(x2)2n,if n is oddif n is even

平方法转换思想

将指数的位,二进制的位,来确定计算哪些幂
$$
x = a * b ^n

\newline
x= a * (b2){\frac{n}{2}}
$$
每次把b进行平方,将n看作一个二进制的数,如果k位为1,则最后的结果需要乘上 b(2k)

b= 13(1101)
x = b 13 = b 1 ∗ b 4 ∗ b 8 x = b^{13} \newline = b^1 * b^{4} * b^8 x=b13=b1b4b8
代码实现

# 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.快速幂应用

计算大指数幂除以一个数的余数,在密码学中应用较多

LeetCode.372超级次方

// 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]
d p [ i ] [ 0 ] = d p [ i − 1 ] [ 0 ] ∗ 3 + d p [ i − 1 ] [ 1 ] ∗ 2 d p [ i ] [ 1 ] = d p [ i − 1 ] [ 0 ] ∗ 2 + d p [ i − 1 ] [ 1 ] ∗ 2 dp[i][0] = dp[i-1][0] * 3 + dp[i-1][1] * 2 \newline dp[i][1] = dp[i-1][0] * 2 + dp[i-1][1] * 2 dp[i][0]=dp[i1][0]3+dp[i1][1]2dp[i][1]=dp[i1][0]2+dp[i1][1]2
边界条件
d p [ 1 ] [ 0 ] = d p [ 1 ] [ 0 ] = 6 dp[1][0] = dp[1][0] = 6 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}

\newline
(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;
  }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值