快速幂Java语言描述[入门级]

(一) 普通快速幂

  • 一般平时我们计算幂次时,都是采用累乘的方法,但这种方法在面临比较大的幂次时,计算效率比较低,时间复杂度为O(n),因此在数据量比较大时,我们要采取更加优化的算法,快速幂就可以很好的解决这个问题.快速幂时间复杂度O( log ⁡ 2 n \log_2^n log2n)
  • 快速幂原理:
    2 10 2^{10} 210为例,按照累乘计算,则需要计算10次
    但是 2 10 2^{10} 210 = 2 8 2^8 28 ∗ {*} 2 2 2^2 22 = 2 8 + 2 2^{8{+}2} 28+2.
    很明显10化为二进制为1010,而8和2都对应该二进制位为1的权重,也就是 2 10 2^{10} 210 = 2 2 3 2^{2^3} 223 ∗ {*} 2 2 1 2^{2^1} 221,此时只需要计算2次,这个在幂次越大时优化越明显.
  • 快速幂模板
public static int pow_Num(int a, int b) {
        int ans = 1;
        while (b != 0) {
            if ((b & 1) != 0) {
                ans = add_Num(ans, a);
            }
            a = add_Num(a, a);
            b >>= 1;
        }
        return ans;
    }
  • a b a^b ab, a = add_Num(a, a)
    a ∗ {*} a = a 2 a^2 a2
    a 2 a^2 a2 ∗ {*} a 2 a^2 a2 = a 4 a^4 a4
    a 4 a^4 a4 ∗ {*} a 4 a^4 a4 = a 8 a^8 a8
    ……
    以此增加权重
  • 除此之外,还可以用快速乘进一步优化,原理和快速幂一样
  • 快速乘
public static int add_Num(int a, int b) {
        int ans = 0;
        while (b != 0) {
            if ((b & 1) != 0) {
                ans = (ans + a) % MOD;
            }
            a = (a + a) % MOD;
            b >>= 1;
        }
        return ans;
    }
import java.util.Scanner;

public class Demo17 {
    static int m;

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        long a = scanner.nextInt();
        long b = scanner.nextInt();
        m = scanner.nextInt();
        System.out.println(pow_Num(a, b));
    }

    private static long pow_Num(long a, long b) {
        long ans = 1;
        while (b != 0) {
            if ((b & 1) != 0) {
                ans = ans * a;
                ans = ans % m;
            }
            a *= a;
            a = a % m;
            b >>= 1;
        }
        return ans;
    }
}

(二) 矩阵快速幂

  • 矩阵快速幂和普通快速幂的原理一样,难点就在于要正确构建矩阵,在此以斐波那契数列作为例题来说明构建矩阵
  • 斐波那契数列:也就是第一项和第二项为1,后面每一项都等于前一项和前两项之和.
    也就是 a n a_n an = a n − 1 a_{n{-}1} an1 + + + a n − 2 a_{n{-}2} an2

a n a_n an = a n − 1 a_{n{-}1} an1 + + + a n − 2 a_{n{-}2} an2
a n − 1 a_{n{-}1} an1 = a n − 1 a_{n{-}1} an1

( 1 1 1 0 ) 1 {\begin{pmatrix} 1&1\\ 1&0\end{pmatrix}}^1 (1110)1 ∗ * ( a n − 1 a n − 2 ) \begin{pmatrix} a_{n{-}1}\\a_{n{-}2}\end{pmatrix} (an1an2) = = = ( a n a n − 1 ) \begin{pmatrix} a_n\\ a_{n{-}1}\end{pmatrix} (anan1)

( 1 1 1 0 ) 2 {\begin{pmatrix} 1&1\\ 1&0\end{pmatrix}}^2 (1110)2 ∗ * ( a n − 2 a n − 3 ) \begin{pmatrix} a_{n{-}2}\\a_{n{-}3}\end{pmatrix} (an2an3) = = = ( a n a n − 1 ) \begin{pmatrix} a_n\\ a_{n{-}1}\end{pmatrix} (anan1)
− − − − − − − − − − − − − − − − − − − − − − − -----------------------
( 1 1 1 0 ) n − 2 ∗ {\begin{pmatrix} 1&1\\ 1&0\end{pmatrix}}^{n{-}2}* (1110)n2 ( a 2 a 1 ) \begin{pmatrix} a_2\\a_1\end{pmatrix} (a2a1) = = = ( a n a n − 1 ) \begin{pmatrix} a_n\\ a_{n{-}1}\end{pmatrix} (anan1)

  • 矩阵快速幂模板
    public static int[][] pow_Mat(int[][] mat, int b) {
        int[][] ans = new int[n][m];
        //单位矩阵
        for (int i = 0; i < n; i++) {
            ans[i][i] = 1;
        }
        while (b != 0) {
            if ((b & 1) != 0) {
                ans = mat_Mul(mat, ans);
            }
            mat = mat_Mul(mat, mat);
            b >>= 1;
        }
        return ans;
    }

    //矩阵乘法
    public static int[][] mat_Mul(int[][] mat, int[][] ans) {
        int[][] res = new int[n][m];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                for (int k = 0; k < n; k++) {
                    res[i][j] += (mat[i][k] * ans[k][j]) % 1000000007;
                }
            }
        }
        return res;
    }
import java.util.Scanner;

public class Demo3 {
    static long n;
    static int a1;
    static int a2;

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        //矩阵行数
        n = scanner.nextLong();
        //矩阵列数
        a1 = scanner.nextInt();
        a2 = scanner.nextInt();
        //构建矩阵
        long[][] mat = new long[][]{{3, 4}, {1, 0}};
        //幂次
        //int b = scanner.nextInt();
        long[][] ints = pow_Mat(mat, n - 2);
        long result = ints[0][0] * a2 + ints[0][1] * a1;
        System.out.println(result % 1000000007);
    }

    public static long[][] pow_Mat(long[][] mat, long b) {
        long[][] ans = new long[mat.length][mat.length];
        //单位矩阵
        for (int i = 0; i < mat.length; i++) {
            ans[i][i] = 1;
        }
        while (b != 0) {
            if ((b & 1) != 0) {
                ans = mat_Mul(mat, ans);
            }
            mat = mat_Mul(mat, mat);
            b >>= 1;
        }
        return ans;
    }

    //矩阵乘法
    public static long[][] mat_Mul(long[][] mat, long[][] ans) {
        long[][] res = new long[mat.length][mat.length];
        for (int i = 0; i < mat.length; i++) {
            for (int j = 0; j < mat.length; j++) {
                for (int k = 0; k < mat.length; k++) {
                    res[i][j] += mat[i][k] * ans[k][j];
                    res[i][j] %= 1000000007;
                }
            }
        }
        return res;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值