蓝桥杯 java组 Day16 快速幂和矩阵快速幂

模运算

        模运算是大数运算中的常用操作。如果一个数太大,无法直接输出,或者不需要直接输出,可以把它取模后,缩小数值再输出。取模也是哈希的常用技术。

定义取模运算为 a 除以 m 的余数,记为:amodm=a

对于 a mod m = a,必须要求 a 和 m 的正负号一致,都为正数或都为负数;如果正负不同,取模和求余的结果是不同的。另外取模的结果满足 0 ≤ a mod m < m−1,题目会用给定的 m,限制计算结果的范围。

取模运算的加减乘除

第一题 快速幂

样例输入

2 10 9

样例输出

7

 总所周知 java里有快速幂库函数

import java.math.BigInteger;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        BigInteger bigInteger1 = scanner.nextBigInteger();
        BigInteger bigInteger2 = scanner.nextBigInteger();
        BigInteger bigInteger3 = scanner.nextBigInteger();
        System.out.println(bigInteger1.modPow(bigInteger2,bigInteger3));
    }
}

 如果不用给的函数做的话:

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int a = scanner.nextInt();
        int n = scanner.nextInt();
        int p = scanner.nextInt();

        int ans = 1;
        while (n != 0) {
            if (n % 2 == 1) {
                ans = (ans * a) % p;
            }
            a = a * a % p;
            n = n / 2;
        }

        System.out.println(ans);
    }
}

第二题 RSA解密

先算出 pq (用java算大数真的很麻烦、改了半天) 但不是很慢 不到一分钟

import java.math.BigInteger;

public class Main {
    public static void main(String[] args) {
        String s = "1001733993063167141";
        BigInteger temp = new BigInteger(s);
        BigInteger bigInteger = new BigInteger(s);
        bigInteger = bigInteger.sqrt();
        BigInteger i = new BigInteger("2");
        BigInteger one = BigInteger.ONE;
        BigInteger zero = BigInteger.ZERO;
        for (; i.compareTo(bigInteger) < 0; ) {
            if (temp.remainder(i).equals(zero)) {
                System.out.println(i);
            }
            i = i.add(BigInteger.ONE);
        }
        System.out.println("END!");
    }
}

891234941   1123984201

接下来求e

import java.math.BigInteger;

public class Main {
    public static void main(String[] args) {
        String s1 = "891234940";
        String s2 = "1123984200";
        String s3 = "212353";
        BigInteger p_1 = new BigInteger(s1);
        BigInteger q_1 = new BigInteger(s2);
        BigInteger d = new BigInteger(s3);
        BigInteger i = BigInteger.ONE;
        while(true){
            if(p_1.multiply(q_1).multiply(i).add(BigInteger.ONE).remainder(d).equals(BigInteger.ZERO)){
                System.out.println(p_1.multiply(q_1).multiply(i).add(BigInteger.ONE).divide(d));
                break;
            }
            i = i.add(BigInteger.ONE);
        }
    }
}

得 e = 823816093931522017

最后求整数X:(用java自带的快速幂库函数)

import java.math.BigInteger;

public class Main {
    public static void main(String[] args) {
        BigInteger e = new BigInteger("823816093931522017");
        BigInteger c = new BigInteger("20190324");
        BigInteger n = new BigInteger("1001733993063167141");
        System.out.println(c.modPow(e,n));
    }
}

x = 579706994112328949

第三题 矩阵的乘法

样例输入

2 1 3
1
2
1 2 3

样例输出

1 2 3
2 4 6

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int N = scanner.nextInt();
        int M = scanner.nextInt();
        int K = scanner.nextInt();

        int[][] k1 = new int[N][M];
        int[][] k2 = new int[M][K];
        int[][] k3 = new int[N][K];

        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                k1[i][j] = scanner.nextInt();
            }
        }

        for (int i = 0; i < M; i++) {
            for (int j = 0; j < K; j++) {
                k2[i][j] = scanner.nextInt();
            }
        }

        for (int i = 0; i < N; i++) {
            for (int j = 0; j < K; j++) {
                int sum = 0;
                for (int k = 0; k < M; k++) {
                    sum = sum + k1[i][k] * k2[k][j];
                }
                k3[i][j] = sum;
            }
        }

        for (int i = 0; i < N; i++) {
            for (int j = 0; j < K; j++) {
                System.out.print(k3[i][j] + " ");
            }
            System.out.println();
        }
    }
}

 第四题 方阵幂次

样例输入

2 2
1 2
3 4

样例输出

7 10
15 22
import java.util.Scanner;

public class Main {
    private static int N;
    private static int M;
    private static int[][] a;

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        N = scanner.nextInt();
        M = scanner.nextInt();
        a = new int[N + 1][N + 1];
        for (int i = 1; i <= N; i++) {
            for (int j = 1; j <= N; j++) {
                a[i][j] = scanner.nextInt();
            }
        }
        int[][] ans = modPow();
        for (int i = 1; i <= N; i++) {
            for (int j = 1; j <= N; j++) {
                System.out.print(ans[i][j] + " ");
            }
            System.out.println();
        }
    }

    private static int[][] modPow() {
        int[][] ans = new int[N + 1][N + 1];
        for (int i = 1; i <= N; i++) {
            ans[i][i] = 1;//单位矩阵
        }
        while (M > 0) {
            if (M % 2 == 1) {
                ans = solve(ans, a);
            }
            M = M / 2;
            a = solve(a, a);
        }
        return ans;
    }

    private static int[][] solve(int[][] a1, int[][] a2) {
        int[][] a3 = new int[N + 1][N + 1];
        for (int i = 1; i <= N; i++) {
            for (int j = 1; j <= N; j++) {
                int sum = 0;
                for (int k = 1; k <= N; k++) {
                    sum = sum + a1[i][k] * a2[k][j];
                }
                a3[i][j] = sum;
            }
        }
        return a3;
    }
}

这种方法对于求幂次高题目来说很快,但如果方阵过大(行列数很大)特别容易超时!

第五题 垒骰子

样例输入

2 1
1 2

样例输出

544

这道题用快速幂的方法(转移矩阵)我属实没看懂、等以后能力够了再来看吧、先用动态规划做出来(因为n过大,动态规划过不了所有的例子,想这道题得满分只能用快速幂)。

貌似用DFS回溯也能做出来(过不了全部数据)

import java.util.Scanner;

public class Main {
    private static int n;
    private static int m;
    private static int[][] a;
    private static int[][] dp;


    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        n = scanner.nextInt();
        m = scanner.nextInt();
        a = new int[m + 1][3];
        dp = new int[n + 1][7];
        for (int i = 1; i <= m; i++) {
            a[i][1] = scanner.nextInt();
            a[i][2] = scanner.nextInt();
        }

        for (int i = 1; i <= 6; i++) {//第一个骰子,每一个面向上的时候,共有四种情况
            dp[1][i] = 4;
        }


        for (int i = 2; i <= n; i++) {
            for (int j = 1; j <= 6; j++) {
                dp[i][j] = solve(i, j);
            }
        }

        System.out.println(dp[n][1] + dp[n][2] + dp[n][3] + dp[n][4] + dp[n][5] + dp[n][6]);
    }

    private static int solve(int i, int j) {
        int ans = 0;
        for (int k = 1; k <= 6; k++) {//k对应着i-1层向上的点数
            int flag = 0;
            for (int l = 1; l <= m; l++) {//l对应着循环遍历a数组
                if ((k == a[l][1] && (j + 3) % 6 == a[l][2]) || (k == a[l][2] && (j + 3) % 6 == a[l][1])) {
                    //说明不符合
                    flag = 1;
                }
            }
            if (flag == 0) {
                ans = ans + dp[i - 1][k];
            }
        }
        return 4*ans;//每个骰子可以旋转四面
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值