2020年第十一届java B组蓝桥杯省赛真题及题解

简介: 蓝桥杯是指蓝桥杯全国软件和信息技术专业人才大赛。是由工业和信息化部人才交流中心举办的全国性IT学科赛事。共有北京大学、清华大学、上海交通大学等全国1200余所高校参赛。

题目:

所有答案均为个人想法 仅供参考,如有问题 欢迎指正


第一题: 解密(5分)

题目描述
小明设计了一种文章加密的方法:对于每个字母 c,将它变成某个另外的字符 Tc。下表给出了字符变换的规则:
在这里插入图片描述

例如,将字符串 YeRi 加密可得字符串 EaFn。
小明有一个随机的字符串,加密后为
EaFnjISplhFviDhwFbEjRjfIBBkRyY
(由 30 个大小写英文字母组成,不包含换行符),请问原字符串是多少?
(如果你把以上字符串和表格复制到文本文件中,请务必检查复制的内容
是否与文档中的一致。在试题目录下有一个文件 str.txt,第一行为上面的字符
串,后面 52 行依次为表格中的内容。)
【答案提交】
这是一道结果填空题,你只需要算出结果后提交即可。本题的结果为一个
只包含 30 个大小写英文字母的字符串,在提交答案时只填写这个字符串,填写
多余的内容将无法得分。


个人答案:

YeRikGSunlRzgDlvRwYkXkrGWWhXaA

解题思路:

在表格中一个字母一个字母的找就可以了。




第二题:纪念日(5分)

题目描述
2020 年 7 月 1 日是中国共产党成立 99 周年纪念日。
中国共产党成立于 1921 年 7 月 23 日。
请问从 1921 年 7 月 23 日中午 12 时到 2020 年 7 月 1 日中午 12 时一共包含多少分钟?
【答案提交】
这是一道结果填空题,你只需要算出结果后提交即可。本题的结果为一个
整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。


个人答案:

52038720

个人代码:

public class Main {

    public static void main(String[] args) {
        int[] mouth = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
        int[] runMouth = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

        //1921年7月23号-31号的天数
        int day = 31 - 23 + 1;
        //1921年8月到12月的天数
        for (int m = 8; m <= 12; ++m) {
            if (runYear(1921)) {
                day += runMouth[m];
            } else {
                day += mouth[m];
            }
        }
        //从1922年-2019年的天数
        for (int year = 1922; year <= 2019; ++year) {
            for (int m = 1; m <= 12; ++m) {
                if (runYear(year)) {
                    day += runMouth[m];
                } else {
                    day += mouth[m];
                }
            }
        }
        //2020年1月-6月的天数
        for (int m = 1; m <= 6; ++m) {
            if (runYear(2020)) {
                day += runMouth[m];
            } else {
                day += mouth[m];
            }
        }
        System.out.println(day * 24 * 60);
    }


    //判断某年是不是闰年
    public static boolean runYear(int year) {
       return year%400==0||year%4==0&&year%100!=0;
    }
    
}

方法二:
在这里插入图片描述

36138 24 60=52038720




第三题:合并检测(10分)

题目描述
新冠疫情由新冠病毒引起,最近在 A 国蔓延,为了尽快控制疫情,A 国准
备给大量民众进病毒核酸检测。
然而,用于检测的试剂盒紧缺。
为了解决这一困难,科学家想了一个办法:合并检测。即将从多个人(k个)采集的标本放到同一个试剂盒中进行检测。如果结果为阴性,则说明这 k个人都是阴性,用一个试剂盒完成了 k 个人的检测。如果结果为阳性,则说明至少有一个人为阳性,需要将这 k 个人的样本全部重新独立检测(从理论上看,如果检测前 k − 1 个人都是阴性可以推断出第 k 个人是阳性,但是在实际操作中不会利用此推断,而是将 k 个人独立检测),加上最开始的合并检测,一共使用了 k + 1 个试剂盒完成了 k 个人的检测。A 国估计被测的民众的感染率大概是 1%,呈均匀分布。请问 k 取多少能最节省试剂盒?
【答案提交】
这是一道结果填空题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。


个人答案:

10

个人代码:

public class Main {

    //因为是均匀分布的,不管一共有多少人,每100人里面就有一个呈现阳性
    //设总人数为n,一共是  n/k组,有0.99*n/k个组呈阳性,有0.01*n/k各组成阴性
    //总共需要的试剂盒个数为: 0.99*n/k+0.01*n/k*(k+1);
    public static void main(String[] args) {

        //假设一共有100人需要检测
        int n = 100;
        //假设当k=1的时候需要测试100次
        int min = 100;
        int mink = 1;
        //分多少组
        int group;
        int temp;
        for (int k = 2; k <= n; ++k) {
            //向上取整
            group = n % k == 0 ? n / k : n / k + 1;
            //向上取整
            int x = group * 0.99 > (int) (group * 0.99) ? (int) (group * 0.99) + 1 : (int) (group * 0.99);
            int y = (group * 0.01 > (int) (group * 0.01) ? (int) (group * 0.01) + 1 : (int) (group * 0.01)) * (k + 1);
            temp = x + y;


            if (temp < min) {
                min = temp;
                mink = k;
            }
        }
        System.out.println(mink);
    }

}




第四题:分配口罩(10分)

题目描述
某市市长获得了若干批口罩,每一批口罩的数目如下:(如果你把以下文字复制到文本文件中,请务必检查复制的内容是否与文档中的一致。在试题目录下有一个文件
mask.txt,内容与下面的文本相同)
9090400
8499400
5926800
8547000
4958200
4422600
5751200
4175600
6309600
5865200
6604400
4635000
10663400
8087200
4554000
现在市长要把口罩分配给市内的 2 所医院。由于物流限制,每一批口罩只能全部分配给其中一家医院。市长希望 2
所医院获得的口罩总数之差越小越好。请你计算这个差最小是多少?
【答案提交】
这是一道结果填空题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。


个人答案:

2400

个人代码:

public class Main {

    static int middleMin = Integer.MAX_VALUE;

    static int sumn = 0;
    static int sum = 0;
    static int min = 0;


    public static void main(String[] args) {
        int[] n = {9090400, 8499400, 5926800, 8547000, 4958200, 4422600, 5751200, 4175600, 6309600, 5865200, 6604400, 4635000, 10663400, 8087200, 4554000};
        int a = 0, b = 0;
        for (int i = 0; i < n.length; ++i) {
            sumn += n[i];
        }


        blackStacking(n, 0);
        System.out.println(min);
    }
//利用递归回溯,尝试所有的组合结果,找里中间值最近的那一个
    static void blackStacking(int[] arr, int n) {

        if (Math.abs(sumn / 2 - sum) < middleMin) {
            middleMin = Math.abs(sumn / 2 - sum);
            min = sumn - sum - sum;
        }

        for (int i = n; i < arr.length; ++i) {
            sum += arr[i];
            blackStacking(arr, i + 1);
            sum -= arr[i];
        }

    }

}




第五题:斐波那契数列最大公约数(15分)

题目描述
在这里插入图片描述


个人答案:

6765

个人代码:


import java.math.BigInteger;
public class Main {

    public static void main(String[] args) {
        BigInteger[] b = new BigInteger[2021];
        b[1] = new BigInteger(String.valueOf(1));
        b[2] = new BigInteger(String.valueOf(1));
        for (int i=3;i<2021;++i){
            b[i]=b[i-1].add(b[i-2]);
        }
        BigInteger gcb = gcb(b[2020], b[520]);
        System.out.println(gcb);
    }

    static BigInteger gcb(BigInteger x, BigInteger y) {
        return x.remainder(y).intValue() == 0 ? y : gcb(y, x.remainder(y));
    }

}




第六题:分类计数(15分)

题目描述
输入一个字符串,请输出这个字符串包含多少个大写字母,多少个小写字母,多少个数字。
【输入格式】
输入一行包含一个字符串。
【输出格式】
输出三行,每行一个整数,分别表示大写字母、小写字母和数字的个数。
【样例输入】
1+a=Aab
【样例输出】
1
3
1
【评测用例规模与约定】
对于所有评测用例,字符串由可见字符组成,长度不超过 100。


个人代码:

import java.util.Scanner;
public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
        int up = 0;
        int low = 0;
        int num = 0;
        for (int i = 0; i < s.length(); ++i) {
            if (s.charAt(i) >= '0' && s.charAt(i) <= '9') {
                num++;
            } else if (s.charAt(i) >= 'A' && s.charAt(i) <= 'Z') {
                up++;
            } else if (s.charAt(i) >= 'a' && s.charAt(i) <= 'z') {
                low++;
            }
        }
        System.out.println(up);
        System.out.println(low);
        System.out.println(num);
    }
   
}




第七题:八次求和(20分)

题目描述
在这里插入图片描述

【输入格式】
输入的第一行包含一个整数 n。
【输出格式】
输出一行,包含一个整数,表示答案。
【样例输入】
2
【样例输出】
257
【样例输入】
987654
【样例输出】
43636805
【评测用例规模与约定】
对于 20% 的评测用例,1 ≤ n ≤ 20。
对于 60% 的评测用例,1 ≤ n ≤ 1000。
对于所有评测用例,1 ≤ n ≤ 1000000。


个人代码:

import java.util.Scanner;
public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int num = sc.nextInt();
        Long l = 0L;
        Long temp = 1L;
        for (int i = 1; i <= num; ++i) {
            temp = 1L;
            for (int j = 0; j < 8; ++j) {
                temp = (temp * i)%123456789;
            }
            l =(l+temp)%123456789;
        }
        System.out.println(l);
    }

}




第八题:字符串编码(20分)

题目描述
小明发明了一种给由全大写字母组成的字符串编码的方法。对于每一个大写字母,小明将它转换成它在 26 个英文字母中序号,即 A → 1, B → 2, … Z →26。这样一个字符串就能被转化成一个数字序列:比如 ABCXYZ → 123242526。现在给定一个转换后的数字序列,小明想还原出原本的字符串。当然这样的还原有可能存在多个符合条件的字符串。小明希望找出其中字典序最大的字
符串。
【输入格式】
一个数字序列。
【输出格式】
一个只包含大写字母的字符串,代表答案
【样例输入】
123242526
【样例输出】
LCXYZ
【评测用例规模与约定】
对于 20% 的评测用例,输入的长度不超过 20。
对于所有评测用例,输入的长度不超过 200000。


个人代码:

import java.util.Scanner;
public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
        char[] c = {0, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
        String str = "";
        String s1;
        for (int i = 0; i < s.length(); ++i) {
            if (s.charAt(i) == '1' && i < s.length() - 1) {
                s1 = s.charAt(i) + "" + s.charAt(i + 1);
                str = str + c[Integer.parseInt(s1)];
                i++;
            } else if (s.charAt(i) == '2' && i < s.length() - 1 && s.charAt(i + 1) <= '6') {
                s1 = s.charAt(i) + "" + s.charAt(i + 1);
                str = str + c[Integer.parseInt(s1)];
                i++;
            } else {
                str += c[s.charAt(i) - 48];
            }
        }
        System.out.println(str);
    }
    
}




第九题:BST 插入节点问题(25分)

题目描述
给定一棵包含 N 个节点的二叉树,节点编号是 1 ∼ N。其中 i 号节点具有权值 Wi,并且这些节点的权值恰好形成了一棵排序二叉树 (BST)。现在给定一个节点编号 K,小明想知道,在这 N 个权值以外,有多少个整数 X (即 X 不等于任何 Wi ) 满足:给编号为 K 的节点增加一个权值为 X 的子节点,仍可以得到一棵 BST。例如在下图中,括号外的数字表示编号、括号内的数字表示权值。编号1 ∼ 4 的节点权值依次是 0、10、20、30。
在这里插入图片描述
如果 K = 1,那么答案为 0。因为 1 号节点已经有左右子节点,不能再增加子节点了。
如果 K = 2,那么答案为无穷多。因为任何一个负数都可以作为 2 的左子节点。
如果 K = 3,那么答案为 9。因为 X = 11, 12, · · · , 19 都可以作为 3 的左子节点。
【输入格式】
第一行包含 2 个整数 N 和 K。
以下 N 行每行包含 2 个整数,其中第 i 行是编号为 i 的节点的父节点编号Pi 和权值 Wi 。注意 Pi = 0 表示 i 是根节点。输入保证是一棵 BST。
【输出格式】
一个整数代表答案。如果答案是无穷多,输出 −1。
【样例输入】
4 3
0 10
1 0
1 20
3 30
【样例输出】
9
【评测用例规模与约定】
对于 60% 的评测用例,1 ≤ K ≤ N ≤ 100,0 ≤ Wi ≤ 200,且 Wi 各不相同。
对于所有评测用例,1 ≤ K ≤ N ≤ 10000,0 ≤ Wi ≤ 100000000,且 Wi 各不相同。


个人代码:

import java.util.*;
public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int k = sc.nextInt();
        int[][] arr = new int[n + 1][2];
        for (int i = 1; i < arr.length; ++i) {
            for (int j = 0; j < arr[i].length; ++j) {
                arr[i][j] = sc.nextInt();
            }
            sc.nextLine();
        }

        //初始化所有的结点
        Node[] nodes = new Node[n + 1];
        for (int i = 1; i < arr.length; ++i) {
            nodes[i] = new Node(i, arr[i][1]);
        }

        //将结点构建成二叉树
        for (int i = 1; i < arr.length; ++i) {

            //只要当前结点不是根节点就有夫结点
            if (arr[i][0] != 0) {
                //如果当前结点的夫结点权值大于当前结点的权值,说明该结点是父节点的左子结点
                if (nodes[arr[i][0]].weight > arr[i][1]) {
                    nodes[arr[i][0]].left = nodes[i];
                }

                //如果当前结点的夫结点权值小于当前结点的权值,说明该结点是父节点的右子结点
                if (nodes[arr[i][0]].weight < arr[i][1]) {
                    nodes[arr[i][0]].right = nodes[i];
                }
            }

        }

        //获取k结点
        Node nodeK = nodes[k];
        int numer = 0;
        boolean isFind = false;
        while (!isFind) {
            //如果当前结点的左右结点都有了就没有办法加了
            if (nodeK.right != null && nodeK.left != null) {
                break;
            }

            //如果当前结点的左节点为空,右结点不为空
            //如果当前结点是父节点的左子树,那么numer=当前结点的右子树的权值-当前结点父节点的权值
            //如果当前结点不是夫结点的左子树,那就需要一直向上找,如果找到根节点都没有找到的话就是无限多个
            if (nodeK.left == null && nodeK.right != null) {
                while (true) {


                    if (nodes[arr[k][0]].weight < nodeK.weight) {
                        numer = nodeK.weight - nodes[arr[k][0]].weight - 1;
                        isFind = true;
                        break;
                    }
                    if (nodes[arr[k][0]].id == 1) {
                        numer = -1;
                        isFind = true;
                        break;
                    }

                    arr[k][0] = arr[nodes[arr[k][0]].id][0];

                }
            }
            //如果当前结点的右节点为空,左结点不为空和上面差不多
            if (nodeK.left != null && nodeK.right == null) {
                while (true) {

                    if (nodes[arr[k][0]].weight > nodeK.weight) {
                        numer = nodeK.weight - nodes[arr[k][0]].weight - 1;
                        isFind = true;
                        break;
                    }
                    if (nodes[arr[k][0]].id == 1) {
                        numer = -1;
                        isFind = true;
                        break;
                    }
                    arr[k][0] = arr[nodes[arr[k][0]].id][0];
                }

            }


            //如果当前结点的左右结点都为空时
            if (nodeK.left == null && nodeK.right == null) {
                int x = 0, y = 0;
                if (nodes[arr[k][0]].id == 1) {
                    numer = -1;
                    break;
                }
                if (nodes[arr[k][0]].left == nodeK) {
                    y = nodes[arr[k][0]].weight;
                    while (true) {
                        if (nodes[arr[k][0]].weight < nodeK.weight) {
                            x = nodes[arr[k][0]].weight;
                            break;
                        }
                        if (nodes[arr[k][0]].id == 1) {
                            numer = -1;
                            break;
                        }
                        arr[k][0] = arr[nodes[arr[k][0]].id][0];
                    }

                } else if (nodes[arr[k][0]].right == nodeK) {
                    x = nodes[arr[k][0]].weight;
                    while (true) {
                        if (nodes[arr[k][0]].weight > nodeK.weight) {
                            y = nodes[arr[k][0]].weight;
                            break;
                        }
                        if (nodes[arr[k][0]].id == 1) {
                            numer = -1;
                            break;
                        }
                        arr[k][0] = arr[nodes[arr[k][0]].id][0];
                    }

                }

                if (numer != -1) {
                    numer = y - x - 1 - 1;
                    isFind = true;
                    break;
                }
            }
        }

        System.out.println(numer);
    }


}

class Node {
    int id;
    int weight;
    Node left;
    Node right;

    public Node(int id, int weight) {
        this.id = id;
        this.weight = weight;
    }
}




第十题:网络分析(25分)

题目描述
小明正在做一个网络实验。他设置了 n 台电脑,称为节点,用于收发和存储数据。初始时,所有节点都是独立的,不存在任何连接。小明可以通过网线将两个节点连接起来,连接后两个节点就可以互相通信了。两个节点如果存在网线连接,称为相邻。小明有时会测试当时的网络,他会在某个节点发送一条信息,信息会发送到每个相邻的节点,之后这些节点又会转发到自己相邻的节点,直到所有直接或间接相邻的节点都收到了信息。所有发送和接收的节点都会将信息存储下来。一条信息只存储一次。给出小明连接和测试的过程,请计算出每个节点存储信息的大小。
【输入格式】
输入的第一行包含两个整数 n, m,分别表示节点数量和操作数量。节点从1 至 n 编号。接下来 m 行,每行三个整数,表示一个操作。如果操作为 1 a b,表示将节点 a 和节点 b 通过网线连接起来。当 a = b时,表示连接了一个自环,对网络没有实质影响。如果操作为 2 p t,表示在节点 p 上发送一条大小为 t 的信息。
【输出格式】
输出一行,包含 n 个整数,相邻整数之间用一个空格分割,依次表示进行完上述操作后节点 1 至节点 n 上存储信息的大小。
【样例输入】
4 8
1 1 2
2 1 10
2 3 5
1 4 1
2 2 2
1 1 2
1 2 4
2 2 1
【样例输出】
13 13 5 3
【评测用例规模与约定】
对于 30% 的评测用例,1 ≤ n ≤ 20,1 ≤ m ≤ 100。
对于 50% 的评测用例,1 ≤ n ≤ 100,1 ≤ m ≤ 1000。
对于 70% 的评测用例,1 ≤ n ≤ 1000,1 ≤ m ≤ 10000。
对于所有评测用例,1 ≤ n ≤ 10000,1 ≤ m ≤ 100000,1 ≤ t ≤ 100。


个人代码:

//看别人的代码是用的 带权并查集,我不会用带权并查集 所以就写了这个简单的方法,时间可能长点 不过挺好理解的
import java.util.*;
public class Main {

    //list集合用于保存 与某个点相连的所有点
    static List<Integer> list = new ArrayList<>();
    //队列 bfs的时候用于保存未遍历的点
    static LinkedList<Integer> queue = new LinkedList<>();

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int[][] op = new int[m][3];
        //grap数组用于保存两个点是否相连,把点与点的相连转化为二维数组
        int[][] grap = new int[n + 1][n + 1];
        //保存每个点的信息
        int[] src = new int[n + 1];
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < 3; ++j) {
                op[i][j] = sc.nextInt();
            }
            sc.nextLine();
        }
        
        for (int i = 0; i < m; ++i) {
            if (op[i][0] == 1) {
                grap[op[i][1]][op[i][2]] = 1;
                grap[op[i][2]][op[i][1]] = 1;
            } else if (op[i][0] == 2) {

                list.clear();
                list.add(op[i][1]);
                bfs(grap, op[i][1]);

                for (Integer integer : list) {
                    src[integer] += op[i][2];
                }
            }
        }

        for (int i = 1; i < src.length; ++i) {
            System.out.print(src[i] + " ");
        }

    }
    //广度优先搜索,遍历跟n点相连的 所有点
    public static void bfs(int[][] grap, int n) {
        if (n > grap.length) {
            return;
        }

        for (int i = 1; i < grap.length; ++i) {
            if (grap[n][i] != 0) {
                if (!list.contains(i)) {
                    list.add(i);
                    queue.add(i);
                }
            }
        }
        if (!queue.isEmpty()) {
            bfs(grap, queue.poll());
        }
    }

}
目录
相关文章
|
8天前
|
人工智能 算法 Java
第十三届蓝桥杯B组Java(试题C:字符统计)
第十三届蓝桥杯B组Java(试题C:字符统计)
56 0
|
7月前
|
算法 Java 测试技术
【备战蓝桥杯 | 软件Java大学B组】十三届真题深刨详解(2)
【备战蓝桥杯 | 软件Java大学B组】十三届真题深刨详解(2)
40 0
|
8天前
|
Java
FEB选择(蓝桥杯JAVA C组)
FEB选择(蓝桥杯JAVA C组)
|
7月前
|
存储 人工智能 Java
【备战蓝桥杯 | 软件Java大学B组】十三届真题深刨详解(1)
【备战蓝桥杯 | 软件Java大学B组】十三届真题深刨详解(1)
383 0
|
8天前
|
Java 数据安全/隐私保护 C++
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-193 Password Suspects(C++&Java)
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-193 Password Suspects(C++&Java)
21 1
|
8天前
|
机器学习/深度学习 Java
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-Java全排列公式
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-Java全排列公式
42 0
|
8天前
|
算法 Java
蓝桥杯算法题——题解Java版本——切面条
蓝桥杯算法题——题解Java版本——切面条
40 0
|
8天前
|
Java
2014年蓝桥杯Java C组——猜年龄
2014年蓝桥杯Java C组——猜年龄
26 0
2014年蓝桥杯Java C组——猜年龄
|
8天前
|
算法 Java 测试技术
蓝桥杯-02-蓝桥杯Java组考点与14届真题
蓝桥杯-02-蓝桥杯Java组考点与14届真题
|
8天前
|
Java
第十三届蓝桥杯B组Java(试题B:山)
第十三届蓝桥杯B组Java(试题B:山)
32 0