模运算
模运算是大数运算中的常用操作。如果一个数太大,无法直接输出,或者不需要直接输出,可以把它取模后,缩小数值再输出。取模也是哈希的常用技术。
定义取模运算为 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;//每个骰子可以旋转四面
}
}