第十三届蓝桥杯大赛软件赛决赛(Java 大学B组)

本文详细解析了蓝桥杯2022年国赛的编程题目,涵盖重合次数、数数、左移右移、窗口、迷宫、小球称重、背包与魔法、修路和围栏等多个算法挑战。通过深入分析解题思路,展示了如何运用广搜、动态规划、模拟等技术解决实际问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

蓝桥杯 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. 1N,M10000.
  对于 100 % \small 100\% 100% 的评测用例, 1 ≤ N , M ≤ 200000 , 1 ≤ x ≤ N . \small 1≤ N,M ≤200000,1≤ x≤ N. 1N,M200000,1xN.


懒惰删除法


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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值