蓝桥杯 2022年国赛真题
Java 大学B组
试题 A: 重合次数
试题 B: 数数
试题 C: 左移右移
试题 D: 窗口
试题 E: 迷宫
试题 F: 小球称重
试题 G: 背包与魔法
试题 H: 修路
试题 I: 围栏
试题 J: 好数之和
虽然名次上有些差强人意,但也算是在不佳的状态下一份不错的答卷了。
更新中…
试题 A: 重合次数
本题总分:5 分
【问题描述】
在同一天中,从上午 6 \small 6 6 点 13 \small 13 13 分 22 \small 22 22 秒到下午 14 \small 14 14 点 36 \small 36 36 分 20 \small 20 20 秒,钟表上的分针和秒针一共重合了多少次?
注意时针、分针、秒针都围绕中心做匀速运动。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个由大写字母组成的字符串,在提交答案时只填写这个字符串,填写多余的内容将无法得分。
494
import java.time.LocalTime;
public class Test {
public static void main(String[] args) {
new Test().run(); }
LocalTime start = LocalTime.of(6, 13, 22);
LocalTime end = LocalTime.of(14, 36, 20);
void run() {
int cnt = 0;
for (; start.compareTo(end) <= 0; start = start.plusSeconds(1))
if (start.getMinute() == start.getSecond() && start.getSecond() != 0) ++cnt;
System.out.println(cnt);
}
}
按秒枚举时间,然后注意一下接近整点时,分针与秒针非常接近一直重合,而题面指出分针、秒针都围绕中心做匀速运动,故而这个地方需要特判一下。
试题 B: 数数
本题总分:5 分
【问题描述】
任何一个大于 1 \small 1 1 的正整数都能被分解为若干个质数相乘,比如 28 = 2 × 2 × 7 \small 28 = 2×2×7 28=2×2×7 被分解为了三个质数相乘。请问在区间 [ \small [ [ 2333333 \small 2333333 2333333 , \small , , 23333333 \small 23333333 23333333 ] \small ] ] 中有多少个正整数 可以被分解为 12 \small 12 12 个质数相乘?
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
25606
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
new Test().run(); }
int cnt = 0, start = 2333333, end = 23333333;
void run() {
int[] factor = new int[end + 1];
List<Integer> prime = new ArrayList();
for (int i = 2; i <= end; ++i) {
if (factor[i] == 0) {
factor[i] = 1;
prime.add(i);
}
if (i >= start &&
factor[i] == 12) ++cnt;
for (int p : prime) {
if (i * p > end) break;
factor[i * p] = factor[i] + 1;
if (i % p == 0) break;
}
}
System.out.print(cnt);
}
}
欧拉筛模板题,没啥好说的。
试题 C: 左移右移
时间限制:3.0s 内存限制:512.0MB 本题总分:10 分
【问题描述】
小蓝有一个长度为 N \small N N 的数组,初始时从左到右依次是 1 , 2 , 3 , ⋯ , N \small 1, 2 , 3, \cdots, N 1,2,3,⋯,N。
之后小蓝对这个数组进行了 M \small M M 次操作,每次操作可能是以下 2 \small2 2 种之一 : : :
1. \small1. 1. 左移 x \small x x,即把 x \small x x 移动到最左边。
2. \small2. 2. 右移 x \small x x,即把 x \small x x 移动到最右边。
请你回答经过 M \small M M 次操作之后,数组从左到右每个数是多少?
【输入格式】
第一行包含 2 2 2 个整数, N N N 和 M M M。
以下 M \small M M 行每行一个操作,其中 “ L x ” \small “L\ x” “L x” 表示左移 x \small x x, “ R x ” \small “R\ x” “R x” 表示右移 x \small x x。
【输出格式】
输出 N \small N N 个数,代表操作后的数组。
【样例输入】
5 3
L 3
L 2
R 1
【样例输出】
2 3 4 5 1
【样例说明】
样例中的数组变化如下 : : :
[ 1 , 2 , 3 , 4 , 5 ] → [ 3 , 1 , 2 , 4 , 5 ] → [ 2 , 3 , 1 , 4 , 5 ] → [ 2 , 3 , 4 , 5 , 1 ] \small [1,2,3,4,5]→[3,1,2,4,5]→[2,3,1,4,5]→[2,3,4,5,1] [1,2,3,4,5]→[3,1,2,4,5]→[2,3,1,4,5]→[2,3,4,5,1]
【评测用例规模与约定】
对于 50 % \small 50\% 50% 的评测用例, 1 ≤ N , M ≤ 10000. \small 1≤ N,M ≤10000. 1≤N,M≤10000.
对于 100 % \small 100\% 100% 的评测用例, 1 ≤ N , M ≤ 200000 , 1 ≤ x ≤ N . \small 1≤ N,M ≤200000,1≤ x≤ N. 1≤N,M≤200000,1≤x≤N.
懒惰删除法
import java.io.PrintWriter;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.ArrayDeque;
import java.util.Deque;
public class Main {
public static void main(String[] args) {
new Main().run(); }
void run() {
PrintWriter out = new PrintWriter(System.out);
Deque<Integer> L = new ArrayDeque();
Deque<Integer> R = new ArrayDeque();
int n = nextInt(), x;
char[] status = new char[n + 1];
for (int m = nextInt(); m-- > 0;)
if (nextChar() == 'L') {
status[x = nextInt()] = 'L';
L.push(x);
} else {
status[x = nextInt()] = 'R';
R.push(x);
}
for (; !L.isEmpty(); L.poll())
if (status[L.peek()] == 'L')
print(out, status, L.peek());
for (int i = 1; i <= n; ++i)
if (status[i] == '\0')
print(out, status, i);
for (; !R.isEmpty(); R.poll())
if (status[R.peek()] == 'R') {
status[R.peek()] = '$';
L.push(R.peek());
}
for (; !L.isEmpty(); L.poll())
print(out, status, L.peek());
out.flush();
}
void print(PrintWriter out, char[] status, int val) {
status[val] = '$';
out.print(val);
out.write(' ');
}
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
StreamTokenizer nextToken() {
try {
in.nextToken();
} catch (IOException e) {
e.printStackTrace();
}
return in;
}
char nextChar() {
return nextToken().sval.charAt(0); }
int nextInt() {
return (int)nextToken().nval; }
}
若我们将 L L L 的操作数通过栈 S S S 存储起来,容易发现经过 M M M 次操作后的数组的前缀,一定是 S S S 自顶向上遍历的结果的一个子序列。
但每个操作数都有可以在某次操作后还被操作若干次,这也导致 S S S 中存储的操作数失去了 “正确性”,不过我们可以仿照 优先队列优化的 D i j k s t r a \small\rm Dijkstra Dijkstra 算法中的懒惰删除法,延迟删除某个操作数之前的操作记录,再效仿次法处理 M M M 次操作后的数组的后缀,
中间则是一段正整数序列的子序列,对于没有懒惰标记的操作数,在处理完结果前缀后依次输出即可。
重排大小
在一些涉及到若干序列的子序列的问题中,如最长公共上升序列,按某个序列的次序重排这个序列出现元素的“大小”是一种常见的处理手段。
容易观察到每次序列次序的变化都是单调易维护的,类似的,我们以每次操作复杂度在一个常数意义下,去维护这么一个“大小”关系序列,就能得到一个上界更为理想的算法。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.io.PrintWriter;
import java.io.IOException;
import static java.util.Arrays.sort;
public class Main {
public static void main(String[] args) {
new Main().run(); }
void run() {
PrintWriter out = new PrintWriter(System.out);
int n = nextInt(), opt, low = 0, high = n;
long[] buffer = new long[n + 1];
for (int m = nextInt(); m-- > 0;) {
opt = nextChar();
buffer[nextInt()] =
opt == 'L' ? --low : ++high;
}
for (int i = 1; i <= n; ++i)
buffer[i] =
buffer[i] == 0 ? (i << 32 | i) : (buffer[i] << 32 | i);
sort(buffer, 1, n + 1);
for (int i = 1; i <= n; ++i) {
out.print((int)buffer[i]);
out.write(' ');
}
out.flush();
}
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
StreamTokenizer nextToken() {
try {
in.nextToken();
} catch (IOException e) {
e.printStackTrace();
}
return in;
}
char nextChar() {
return nextToken().sval.charAt(0); }
int nextInt() {
return (int)nextToken().nval; }
}
试题 D: 窗口
时间限制:3.0s 内存限制:512.0MB 本题总分:10 分
【问题描述】
在平时使用电脑的过程中,经常会打开各种各样的窗口,各个窗口会在桌面上重叠,并按照一定的层次关系显示。有的窗口能够看到全部内容,而有的窗口只能看到局部。
现在给定一组操作桌面窗口的过程序列,请你通过 A S C I I \footnotesize\rm ASCII ASCII 艺术图来绘制最后桌面的状态。
已知桌面的大小为 N × M \small N × M N×M,即桌面高度为 N \small N N 个像素,宽度为 M \small M