- 非常
nice
,去年C++
国赛填空题我全错喜提国三,今年javaB
组填空题依旧全错,稳定发力(bushi
试题 A: 星期计算
-
已知今天是星期六,请问 2 0 22 20^{22} 2022 天后是星期几?
-
答案:
7
用python
跑出来结果为
>>> (20 ** 22) % 7 + 6
7
不好意思我是sb,第一遍题解刚刚写错了
试题 B: 山
- 求
[2022, 2022222022]
中先单调不减,后单调不增的回文数的数量 - 答案:
3138
错误答案:120101
我个笨比题目没读完,读成回文数的数量了
试题 C: 字符统计
-
题意:给定一个仅由大写字母组成的字符串,求出现次数最多的字母
-
拿
26
个桶cnt[]
计数一下每个字母出现的数量,再for
一遍求出最大的桶的容量ans
,然后最后for
一遍看有哪些桶的容量等于ans
输出答案
import java.util.Scanner;
public class C {
static int cnt[] = new int[30];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.next();
int len = s.length();
char now;
for(int i = 0; i < len; i ++ )
{
now = s.charAt(i);
cnt[(int)(now - 'A')] ++;
}
int ans = -1;
for (int i = 0; i < 26; i++) {
if(cnt[i] > ans)
ans = cnt[i];
}
for (int i = 0; i < 26; i++) {
if(cnt[i] == ans)
{
now = (char)(i + 'A');
System.out.print(now);
}
}
// BABBACAC
}
}
试题 D: 最少刷题数
-
题意:
n
个人,每个人该学期的刷题数量为a[i]
,问对于每一个人,他最少需要再刷多少题,才能使得题数比他大的人不超过题数比他少的人。其中 1 ≤ n ≤ 1 0 6 1\le n \le 10^6 1≤n≤106。 -
这题我卡了很久,也不知道我考场的时候在犯什么
sb
-
此处先约定,下标从
0
开始,即0~(n-1)
。很显然的一个思路就是先排序一遍,然后根据中位数a[n / 2 + 1 - 1]
,即a[n / 2]
来判断。我们约定u = a[n / 2]
,注意,当你的成绩等于中位数u
(向上取整的那个)的时候不一定满足条件,你可能还需要再刷题,比如4 4 4 4 5
,比中位数4
大的数有1
个,比它小的有0
个 -
但是你当你的目标达到
u + 1
的时候是一定满足条件的 -
我们通过另一个数组
b
来保存原来的a
数组 -
所以我们得特判
b[i] = u
的情况,统计整个数组中比u
大的数的数量mx
,比u
小的数量mi
。
- 对于
b[i] == u
的这些人,我们讨论它的目标设置的题数- 如果
mx <= mi
的话,则你不刷题也能满足条件,即目标题数为u
题 - 反之,则说明这些人需要再刷
1
题,即目标题数为u + 1
题
- 如果
- 对于
b[i] < u
的这些人- 如果
mx <= mi - 1
,则这些人的目标题数为u
题。因为这个人从一个比u
小的数变为u
,那么mi
也会减小1
,所以mx <= mi - 1
即代表变为u
后满足条件,目标题数为u
题 - 反之,这些人的题数必须定为
u + 1
题
- 如果
- 对于
b[i] > u
的这些人,不需要刷任何题目也能满足条件
- 我考场的时候大概就是这样的写的,一开始没有梳理清楚,以至于我非常乱,写完删又写又改的,这种题目应该先想清楚再写
import java.util.Arrays;
import java.util.Scanner;
public class D {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int a[] = new int[n];
int b[] = new int[n];
for (int i = 0; i < n; i++) {
a[i] = sc.nextInt();
b[i] = a[i];
}
if (n == 1) {
System.out.print(0);
return;
}
Arrays.sort(a);
int u = a[n / 2];
int lessAns, equAns;
int mi = 0, mx = 0;
for (int i = 0; i < n; i++) {
if (b[i] < u)
mi++;
if (b[i] > u)
mx++;
}
if (mx <= mi) {//==u 的为0
equAns = 0;
} else {
equAns = 1;
}
if (mx <= mi - 1) { // < u 的达到u即是答案
lessAns = u;
} else {
lessAns = u + 1;
}
for (int i = 0; i < n; i++) {
if (i > 0) {
System.out.print(' ');
}
if (b[i] > u) {
System.out.print(0);
} else if (b[i] < u) {
System.out.print(lessAns - b[i]);
} else {
System.out.print(equAns);
}
}
}
}
试题 E: 求阶乘
- 题意:
n!
尾数恰好有k
个零,求最小的n
,若n
不存在,则输出-1
。其中 1 ≤ k ≤ 1 0 18 1\le k \le10^{18} 1≤k≤1018。 - 考虑因数分解,只有
2/5
两个质因数可以造出0
,但是2
的数量远远大于5
的数量,所以我们只需要统计5
的数量 - 可以发现因子
5
是每5
个加1
,每25
个加2
,每125
个加3
……每隔5 ^ i
加i
,最后贡献和为k
的时候即是答案。这样我可以发现5
和25
的贡献会重复掉,故我们可以像叠积木一样计算,先把5
的地基打上一层为n / 5
,再打上25
的贡献为n / 25
,以此类推,最后可以算出累加和now
- 我们可以发现,有单调性,
n
越大,后面跟着的0
越多,区间满足单调性(二段性,前半段零的数量比k
少,后半段比k
多),故可以二分 - 但是注意二分边界不能设置
r = 1e18
需要设r = 9e18
(考场上我是写这个数字的,但是实际上只需要5e18
即可),因为1e18
的阶乘后面的0
的数量不到1e18
- 注意二分出来的答案,如果
now = k
也不一定是最小的答案,需要最大的小于它的5
的倍数 - 我考场的代码如下:
import java.util.Scanner;
public class Main {
final static long f[] = new long[]{1L, 5L, 25L, 125L, 625L, 3125L, 15625L, 78125L, 390625L, 1953125L, 9765625L, 48828125L, 244140625L, 1220703125L, 6103515625L, 30517578125L, 152587890625L, 762939453125L, 3814697265625L, 19073486328125L, 95367431640625L, 476837158203125L, 2384185791015625L, 11920928955078125L, 59604644775390625L, 298023223876953125L, 298023223876953125L * 5L};
public static long check(long mid)
{
long res = 0;
for(int i = 1; i < f.length; i ++)
{
res += mid / f[i];
}
return res;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
long num = sc.nextLong();
// System.out.println(check((long)9e18) /(long)1e18);
// System.out.println(Long.MAX_VALUE);
// System.out.println(f[f.length - 1] / (long)(1e18));
long l = 1, r = (long)9e18;
long mid;
long now;
while(l < r)
{
mid = (l + r) >> 1;
now = check(mid);
if(now < num)
{//说明需要再增加
l = mid + 1;
}
else
{
r = mid;
}
}
if(check(r) == num)
System.out.print(r);
else
System.out.print(-1);
}
}
试题 F: 最大子矩阵
- 给定一个
n * m
的矩阵,求解满足矩阵内最大值与最小值的差值不超过limit
的最大面积的矩阵 - 一开始觉得是单调栈,但是考场时间不够了,没时间细想,于是就直接写了一个四维的
dp
了 - 暴力做法如下,大致能拿
50%
的分数
import java.util.Scanner;
public class F {
static int n, m;
static int limit;
//F题
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
int a[][] = new int[n][m];
for (int i = 0; i < n; i++) {
a[i] = new int[m];
for (int j = 0; j < m; j++) {
a[i][j] = sc.nextInt();
}
}
int dp[][][][] = new int[n][m][n][m];
int dp2[][][][] = new int[n][m][n][m];
limit = sc.nextInt();
for (int lx = 0; lx < n; lx++) {
dp[lx] = new int[m][n][m];
dp2[lx] = new int[m][n][m];
for (int ly = 0; ly < m; ly++) {
dp[lx][ly] = new int[n][m];
dp2[lx][ly] = new int[n][m];
for (int rx = lx; rx < n; rx++) {
dp[lx][ly][rx] = new int[m];
dp2[lx][ly][rx] = new int[m];
if (lx != rx) {
dp[lx][ly][rx][ly] = Math.max(dp[lx][ly][rx - 1][ly], a[rx][ly]);
dp2[lx][ly][rx][ly] = Math.min(dp2[lx][ly][rx - 1][ly], a[rx][ly]);
for (int ry = ly + 1; ry < m; ry++) {
dp[lx][ly][rx][ry] = Math.max(a[rx][ry], dp[lx][ly][rx][ry - 1]);
dp[lx][ly][rx][ry] = Math.max(dp[lx][ly][rx][ry], dp[lx][ly][rx - 1][ry]);
dp2[lx][ly][rx][ry] = Math.min(a[rx][ry], dp2[lx][ly][rx][ry - 1]);
dp2[lx][ly][rx][ry] = Math.min(dp2[lx][ly][rx][ry], dp2[lx][ly][rx - 1][ry]);
// System.out.println(lx + " " + ly + " " + rx + " " + ry + " : " + dp[lx][ly][rx][ry]);
}
} else {//lx == rx
dp[lx][ly][rx][ly] = a[rx][ly];
dp2[lx][ly][rx][ly] = a[rx][ly];
for (int ry = ly + 1; ry < m; ry++) {
dp[lx][ly][rx][ry] = Math.max(a[rx][ry], dp[lx][ly][rx][ry - 1]);
dp2[lx][ly][rx][ry] = Math.min(a[rx][ry], dp2[lx][ly][rx][ry - 1]);
// System.out.println(lx + " " + ly + " " + rx + " " + ry + " : " + dp[lx][ly][rx][ry]);
}
}
}
}
}
int sx, sy;
int ans = Integer.MIN_VALUE;
for (int lx = 0; lx < n; lx++) {
for (int ly = 0; ly < m; ly++) {
for (int rx = lx; rx < n; rx++) {
for (int ry = ly; ry < m; ry++) {
if(dp[lx][ly][rx][ry] - dp2[lx][ly][rx][ry] <= limit)
{
sx = rx - lx + 1;
sy = ry - ly + 1;
ans = Math.max(ans, sx * sy);
}
}
}
}
}
System.out.print(ans);
}
}
试题 G: 数组切分
-
将一个由
1~n
的排序划分为若干个连续的子数组,且每一段都是连续的自然数的方案数。其中 1 ≤ n ≤ 1 0 4 1\le n \le 10^4 1≤n≤104。 -
第一反应是
dp
,但是前面编程题卡太久了,没时间细想了,于是写了暴搜,大概拿了30%
的分数。
import java.util.Scanner;
public class Main {
final static long md = (long)(1e9 + 7);
static int a[] = new int [30];
static int n;
static long ans = 0;
static boolean used[] = new boolean[30];
static boolean vis[] = new boolean[30];
public static void dfs(int head, int h)
{
if(h == n + 1)
{
if(head == h)
{
ans = (ans + 1) % md;
}
return ;
}
dfs(head, h + 1);
//继续向下加
int mx = Integer.MIN_VALUE;
int mi = Integer.MAX_VALUE;
for(int i = 1; i <= n; i ++)
{
vis[i] = false;
}
for(int i = head; i <= h; i ++ )
{
mi = Math.min(a[i], mi);
mx = Math.max(a[i], mx);
vis[a[i]] = true;
}
for (int i = mi; i <= mx ; i++) {
if(!vis[i])
{
return ;
}
}
dfs(h + 1, h + 1);
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
if(n > 20)
{
return ;
}
for (int i = 1; i <= n; i++) {
a[i] = sc.nextInt();
}
dfs(1, 1);
System.out.print(ans);
}
}
试题 H: 回忆迷宫
- 这题我跳了
试题 I: 红绿灯
- 写了
30%
的暴力做法,只有一段能冲刺,枚举是哪一段
import java.util.Scanner;
public class I {
static int n, m ,k, v;
static int a[] = new int[1010];
static int b[] = new int[1010];
static int c[] = new int[1010];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
k = sc.nextInt();
v = sc.nextInt();
for (int i = 0; i < m; i++) {
a[i] = sc.nextInt();
b[i] = sc.nextInt();
c[i] = sc.nextInt();
}
a[m] = n;
int ans = Integer.MAX_VALUE;
int zq;
for (int i = 0; i <= m; i++) {
int now = 0;
int last = 0;
//表示到达i前是否冲刺
for (int j = 0; j <= m; j++) {
if(i != j)
{//不冲刺
now += a[j] - last;
//走这一段
}
if(j == m)
{
break;
}
last = a[j];
zq = b[j] + c[j];
int s = now % zq;
if(s >= b[j])
{//红灯时间
now += zq - s;
}
}
// System.out.println(now);
ans = Math.min(now, ans);
}
System.out.print(ans);
}
}
/*
90 2 2 2
30 20 20
60 20 20
350 2 100 1
50 50 10
250 60 200
260
350 2 100 1
50 50 10
250 60 20
*/
试题 J: 拉箱子
考试剩下最后 5 5 5分钟了,原本想写一个搜索的,我索性直接交上去一个随机数了
import java.util.Scanner;
public class Main {
static int n, m, k, v;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
int a[][] = new int[n][m];
for (int i = 0; i < n; i++) {
a[i] = new int[m];
for (int j = 0; j < m; j++) {
a[i][j] = sc.nextInt();
}
}
double ans = Math.random() * (n * m - 1);
ans += 1;
int l = (int) ans;
System.out.println(l);
}
}