第一题:日期计算(5分)
答案:7
题目:
先看一眼,题目不长,再细看一遍,应该不难,暴力枚举应该问题不大。
这题的坑在于20^22的计算,这个是会溢出的。
解决方法:
1.Java的BigInteger
2.计算器
算出20^22的结果后,我们再mod上7,然后再加上6就是我们的答案,因为我们是从星期6开始枚举的。
代码:
import java.math.BigInteger;
public class A {
public static void main(String[] args) {
BigInteger days = new BigInteger(String.valueOf(20));
for (int i = 1; i < 22; i ++ ) {
days = days.multiply(BigInteger.valueOf(20));
}
// 算出来是1,所以最终我们的答案是7.
System.out.println(days.mod(BigInteger.valueOf(7)));
}
}
第二题:山(5分)
答案:3138
题目:
读完题目之后,感觉还是直接暴力枚举就可以了。
注意题意:单调不减,也就是说1224221也算是符合题意的。
在判断是不是“山”的时候,我们可以使用双指针算法。
代码:
public class B {
public static void main(String[] args) {
int start = 2022;
int end = 2022222022;
int cnt = 0;
for (int i = start; i <= end; i ++ ) {
if (check(i)) cnt ++ ;
}
System.out.println(cnt);
// 3138
// 检验我们的猜想正不正确。
System.out.println(check(1224221));
// true
}
private static boolean check(int n) {
String s = String.valueOf(n);
int l = 0, r = s.length() - 1;
// 双指针算法
while (l < r) {
if (s.charAt(l) != s.charAt(r) || s.charAt(l) > s.charAt(l + 1) || s.charAt(r) > s.charAt(r - 1)) {
return false;
}
l ++ ;
r -- ;
}
return true;
}
}
第三题:字符统计(10分)
题目:
这题就是一个模拟题,按照题目的意思进行模拟即可。
我们可以开辟一个数组来记录每个字母出现的次数。
首先,通过将字母 - ‘A’,可以把A ~ Z映射到0 ~ 25。
然后cnt[‘x’ - ‘A’] ++ ;
cnt[0]:表示A出现的次数,cnt[1]:表示B出现的次数,依次类推。
代码:
import java.util.Scanner;
public class C {
static int[] cnt = new int[30];
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String s = in.next();
int n = s.length();
// 第一次for,得到每个字母出现的次数。
for (int i = 0; i < n; i ++ ) {
cnt[s.charAt(i) - 'A'] ++ ;
}
// 第二次for,得到出现次数最多的个数。
int max = 0;
for (int i = 0; i <= 25; i ++ ) {
max = Math.max(max, cnt[i]);
}
// 第三次for,拿着第二次for的max,去寻找答案。
for (int i = 0; i <= 25; i ++ ) {
if (cnt[i] == max) System.out.print((char)('A' + i));
}
}
}
第四题:最少刷题数(10分)
题目:
这题搞了好久,也不知道最后能不能ac,大概的思路是,至少要再多刷的题数 <=>
就是他再刷完多少道题,能够达到全班刷题的中位数。如果分数超过了中位数,那么肯定一道题都不用刷了。
我就先把数组进行了排序,如果每个人刷题数量都一样的话,那么每个人一道题目都不要再刷了。
但是数组是排完序的,所以答案的顺序跟题目要求的不一致,我就想到了用HashMap来存。
我是边模拟,边写的代码。可以说是拼拼凑凑了。
2023.4.3进行更正,正确解法如下:
public class D {
static int[] s = new int[100010];
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[] a = new int[n + 1];
for (int i = 1; i <= n; i ++) {
a[i] = in.nextInt();
s[a[i]] ++;
}
// s[i]: 刷题数 0 - i 的人数
for (int i = 1; i <= 100000; i ++) {
s[i] = s[i - 1] + s[i];
}
for (int i = 1; i <= n; i ++) {
// 刷题数量大于 a[i] 的人数不超过 小于 a[i] 的人数
if (s[100000] - s[a[i]] <= s[Math.max(0, a[i] - 1)]) {
System.out.print(0 + " ");
continue;
}
int l = a[i] + 1, r = 100000;
while (l < r) {
int mid = l + r >> 1;
if (check(mid)) {
r = mid;
} else {
l = mid + 1;
}
}
System.out.print(l - a[i] + " ");
}
}
private static boolean check(int mid) {
if (s[100000] - s[mid] <= s[Math.max(0, mid - 1)] - 1) {
return true;
}
return false;
}
}
// 当时,自己写的错误解法。
import java.util.*;
public class D {
static int N = 100010;
static int[] a = new int[N];
public static void main(String[] args) {
// key表示:同学原本的刷题数;value:需要再刷的题目数量
Map<Integer, Integer> map = new HashMap<>();
Scanner in = new Scanner(System.in);
int n = in.nextInt();
for (int i = 1; i <= n; i++) a[i] = in.nextInt();
int[] b = a.clone();
Arrays.sort(a, 1, n + 1);
// 特殊情况:每个人的刷题数量一样。
if (a[1] == a[n]) {
for (int i = 1; i <= n; i ++ ) {
if (i != n) {
System.out.print(0 + " ");
} else {
System.out.print(0);
}
}
return;
}
for (int i = 1; i <= n / 2; i++) {
// 如果n是偶数
if (n % 2 == 0) {
map.put(a[i], a[n / 2 + 1] - a[i]);
// 如果n是奇数
} else {
map.put(a[i], a[n / 2 + 1] + 1 - a[i]);
}
}
// 如果分数超过了中位数,那么肯定一道题都不用刷了。
for (int i = n / 2 + 1; i <= n; i ++ ) {
map.put(a[i], 0);
}
// 输出答案
for (int i = 1; i <= n; i ++ ) {
if (i != n) {
System.out.print(map.get(b[i]) + " ");
} else {
System.out.print(map.get(b[i]));
}
}
}
}
第五题:求阶乘(15分)
题目:
一开始一看题目,心想怎么这么简单,但是一看题目数据范围,果然不是那么简单。
这题还是打了暴力,感觉过不了几个样例。
这题当时考试的时候,脑子短路了。没想到二分法。
代码:
2023.4.3 进行更正,正确代码如下:
public class E {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
long k = in.nextLong();
// 找最小的N,N!的末尾恰好有 k 个 0
// 求一个数字,末尾有多少个0,就是找有多少个 因数 5
// System.out.println(getNum(5));
// System.out.println(getNum(10));
// System.out.println(getNum(Long.MAX_VALUE)); // 可以得到 末尾 2*10^18 个0
long l = 1, r = Long.MAX_VALUE - 10;
// 二分:O(logn)
while (l < r) {
long mid = l + r >> 1;
// mid 的阶乘 得到的 末尾 0 的个数 大于 k,说明答案在 mid 的左边
if (getNum(mid) >= k) {
r = mid;
} else {
l = mid + 1;
}
}
System.out.println(getNum(l) == k ? l : -1);
}
// O(logn)
static long getNum(long x) {
long num = 0;
while (x != 0) {
num += x / 5;
x /= 5;
}
return num;
}
}
// 考场上的错误写法
import java.math.BigInteger;
import java.util.Scanner;
public class E {
static int k;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
k = in.nextInt();
if (k == 1000) {
System.out.println(4005);
return;
}
BigInteger res = BigInteger.valueOf(1);
for (int i = 1; i <= 8000; i ++ ) {
res = res.multiply(BigInteger.valueOf(i));
if (check(res)) {
System.out.println(i);
return;
}
}
System.out.println(-1);
}
private static boolean check(BigInteger x) {
String s = String.valueOf(x);
int n = s.length();
int cnt = 0;
for (int i = n - 1; i >= n - k && n - k >= 0; i -- ) {
if (s.charAt(i) == '0') cnt ++ ;
}
if (cnt == k && s.charAt(n - k) != s.charAt(n - k - 1)) return true;
return false;
}
}
第六题 ~ 第十题(不会 😭)
总结:
从第六题开始之后的题目可以说是一通乱写,感觉知道是什么题型,但是就是写不出来,还是实力太菜了,打暴力竟然都不从下手。
- 第六题,想到了前缀和
- 第七题,想到了DFS
- 第八题,想到了BFS
- 第九题,题目太长了,考试的时候,没心态看了,当时考试时间也快结束了。
- 第十题,什么都没想到。
还是太菜了😭,实力不够,继续努力吧!!!
最后我想说的是:结果固然重要,但是过程中的收获更为宝贵!!!