蓝桥杯Java_B组真题

本文介绍了多种算法在实际问题中的应用,包括字符串处理、数列求值、数的分解、迷宫寻路、特定数字求和、外卖优先级分析、人物相关性分析等。通过对这些实例的解析,展示了如何利用Java实现算法解决问题,涉及数据结构、搜索策略和数学计算等多个方面。

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

刚开始学算法,有些代码是网上搜下来思路自己打的,因为是看了就关了网页,借鉴的代码已经找不到了,如果有人发现可以提醒我加上其他原博主链接

2019

B_不同字串

本题总分:5 分
【问题描述】
一个字符串的非空子串是指字符串中长度至少为 1 的连续的一段字符组成 的串。例如,字符串aaab 有非空子串a, b, aa, ab, aaa, aab, aaab,一共 7 个。 注意在计算时,只算本质不同的串的个数。 请问,字符串0100110001010001 有多少个不同的非空子串?

本题可以利用java中set集合的自动去重性质

import java.util.HashSet;
import java.util.Set;

public class B_不同字串 {
    public static void main(String[] args) {
        String s ="0100110001010001";
        //定义 HashSet类型,自动去重
        Set<String> set= new HashSet<String>();
        for (int i = 0;i<s.length();i++){
            for (int j = i+1;j<=s.length();j++){
                //substring(i,j) 表示截取第i到第j-1下标的子串
                String temp = s.substring(i,j);
                //将 temp 添加到 HashSet 集合中,有重复的会去重
                set.add(temp);
            }
        }
        //set集合长度即为不同字串的个数
        System.out.println(set.size());
    }
}

C_数列求值

本题总分:10 分
【问题描述】
给定数列 1, 1, 1, 3, 5, 9, 17, …,从第 4 项开始,每项都是前 3 项的和。求 第 20190324 项的最后 4 位数字。

【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一 个 4 位整数(提示:答案的千位不为 0),在提交答案时只填写这个整数,填写 多余的内容将无法得分。

本题有些类似斐波那锲数列,但是却存不了这么大的数字,根据提示,本题应该只与后四位有关,所以只求后四位即可

原本想利用BIgInteger做,后来运算出来发现超时

    public static void main(String[] args) {
        int i = 1, j = 1, k = 1;
        //类似于斐波那锲,但数值过大,不能直接运算,模10000,只求出最后4位数字
        for (int a = 4; a <= 20190324; a++) {
            int temp = (i + j + k) % 10000;
            i = j;
            j = k;
            k = temp;
        }
        System.out.println(k);
    }

D_数的分解

把 2019 分解成 3 个各不相同的正整数之和,并且要求每个正整数都不包 含数字 2 和 4,一共有多少种不同的分解方法? 注意交换 3 个整数的顺序被视为同一种方法,例如 1000+1001+18 和 1001+1000+18 被视为同一种。

可以利用三次循环,每个循环中的数都比上层循环大,这样就不会重复整数顺序

public class D {
    /**
     * @param num 表示需要判断的正整数
     * @return false表示含有 2或者4 ,true表示不含有
     */
    static boolean get24(int num) {
        int temp = 0;
        while (num > 0) {
            temp = num % 10;
            if (temp == 2 || temp == 4) {
                return false;
            }
            num = num / 10;
        }
        return true;
    }

    public static void main(String[] args) {
        int num = 0;
        //将i,j,k 分为三个不同的数字,这样做的好处是不用去重
        for (int i = 1; i <= 2019; i++) {
            for (int j = i + 1; j <= 2019; j++) {
                for (int k = j + 1; k <= 2019; k++) {
                    if (i + j + k == 2019 && get24(i) && get24(j) && get24(k)) {
                        num++;
                    }
                }
            }
        }
        System.out.println(num);
    }
}

E_迷宫

下图给出了一个迷宫的平面图,其中标记为 1 的为障碍,标记为 0 的为可 以通行的地方。

010000
000100
001001
110000

迷宫的入口为左上角,出口为右下角,在迷宫中,只能从一个位置走到这 个它的上、下、左、右四个方向之一。 对于上面的迷宫,从入口开始,可以按DRRURRDDDR 的顺序通过迷宫, 一共 10 步。其中 D、U、L、R 分别表示向下、向上、向左、向右走。 对于下面这个更复杂的迷宫(30 行 50 列),请找出一种通过迷宫的方式, 其使用的步数最少,在步数最少的前提下,请找出字典序最小的一个作为答案。 请注意在字典序中D<L<R<U。

              "01010101001011001001010110010110100100001000101010"
              "00001000100000101010010000100000001001100110100101"
              "01111011010010001000001101001011100011000000010000"
              "01000000001010100011010000101000001010101011001011"
              "00011111000000101000010010100010100000101100000000"
              "11001000110101000010101100011010011010101011110111"
              "00011011010101001001001010000001000101001110000000"
              "10100000101000100110101010111110011000010000111010"
              "00111000001010100001100010000001000101001100001001"
              "11000110100001110010001001010101010101010001101000"
              "00010000100100000101001010101110100010101010000101"
              "11100100101001001000010000010101010100100100010100"
              "00000010000000101011001111010001100000101010100011"
              "10101010011100001000011000010110011110110100001000"
              "10101010100001101010100101000010100000111011101001"
              "10000000101100010000101100101101001011100000000100"
              "10101001000000010100100001000100000100011110101001"
              "00101001010101101001010100011010101101110000110101"
              "11001010000100001100000010100101000001000111000010"
              "00001000110000110101101000000100101001001000011101"
              "10100101000101000000001110110010110101101010100001"
              "00101000010000110101010000100010001001000100010101"
              "10100001000110010001000010101001010101011111010010"
              "00000100101000000110010100101001000001000000000010"
              "11010000001001110111001001000011101001011011101000"
              "00000110100010001000100000001000011101000000110011"
              "10101000101000100010001111100010101001010000001000"
              "10000010100101001010110000000100101010001011101000"
              "00111100001000010000000110111000000001000000001011"
              "10000001100111010111010001000110111010101101111000"

获取最短路径利用BFS,走过的路径可以用栈存储,顺着终点找起点,然后再将字符串反转即可

package _2019;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

public class E_迷宫 {
    public static void main(String[] args) {
            String s = "01010101001011001001010110010110100100001000101010"
                    + "00001000100000101010010000100000001001100110100101"
                    + "01111011010010001000001101001011100011000000010000"
                    + "01000000001010100011010000101000001010101011001011"
                    + "00011111000000101000010010100010100000101100000000"
                    + "11001000110101000010101100011010011010101011110111"
                    + "00011011010101001001001010000001000101001110000000"
                    + "10100000101000100110101010111110011000010000111010"
                    + "00111000001010100001100010000001000101001100001001"
                    + "11000110100001110010001001010101010101010001101000"
                    + "00010000100100000101001010101110100010101010000101"
                    + "11100100101001001000010000010101010100100100010100"
                    + "00000010000000101011001111010001100000101010100011"
                    + "10101010011100001000011000010110011110110100001000"
                    + "10101010100001101010100101000010100000111011101001"
                    + "10000000101100010000101100101101001011100000000100"
                    + "10101001000000010100100001000100000100011110101001"
                    + "00101001010101101001010100011010101101110000110101"
                    + "11001010000100001100000010100101000001000111000010"
                    + "00001000110000110101101000000100101001001000011101"
                    + "10100101000101000000001110110010110101101010100001"
                    + "00101000010000110101010000100010001001000100010101"
                    + "10100001000110010001000010101001010101011111010010"
                    + "00000100101000000110010100101001000001000000000010"
                    + "11010000001001110111001001000011101001011011101000"
                    + "00000110100010001000100000001000011101000000110011"
                    + "10101000101000100010001111100010101001010000001000"
                    + "10000010100101001010110000000100101010001011101000"
                    + "00111100001000010000000110111000000001000000001011"
                    + "10000001100111010111010001000110111010101101111000";
            int[][] labyrinth = new int[30][50];

            //给labyrinth数组赋值
            //将字符 - '0' ,可以得到字符相应的int值,若不转换,则全部输出 0
            for (int i = 0; i < 30; i++) {

                for (int j = 0; j < 50; j++) {
                    labyrinth[i][j] = s.charAt(50 * i + j) - '0';
                }
            }

            System.out.println(BFS(labyrinth, 30, 50));
        }

    public static String BFS(int[][] labyrinth, int row, int column) {
        int[][] stepArr = {{-1, 0}, {0, 1}, {0, -1}, {1, 0}};
        String[] direction = {"U", "R", "L", "D"};
        int[][] visit = new int[row][column];// 标记是否已经访问过
        //用来拼接路径,并且反转字符串路径
        StringBuilder sb = new StringBuilder();
        //Node为自定义的对象类型
        Node node = new Node(0,0,-1,-1,0,null);
        //Queue是队列
        Queue<Node> queue = new LinkedList<Node>();
        Stack<Node> stack = new Stack<Node>();
        //向 queue队列添加 node元素
        queue.offer(node);
        while (!queue.isEmpty()) {
            //弹出队头元素,赋值给 head
            Node head = queue.poll();
            //将head压栈到 stack
            stack.push(head); // 用于回溯路径
            //将此坐标标记为已访问
            visit[head.x][head.y] = 1;
            //判断方向,做出相关处理
            for (int i = 0; i < 4; i++) {
                int x = head.x + stepArr[i][0];
                int y = head.y + stepArr[i][1];
                //d表示方向路径
                String d = direction[i];
                // 当到达终点时
                if (x == row - 1 && y == column - 1 && labyrinth[x][y] == 0 && visit[x][y] == 0) {
                    // 打印路径,弹栈,即最后一步到达终点前,到达终点的这一步不进行压栈
                    Node top = stack.pop();
                    //打印到达终点的最后一步的方向,顺着终点找回起点,最后再将字符串反转即可
                    sb.append(d);
                    //上一步的方向
                    sb.append(top.direction);

                    //上一步的坐标,因为是从终点找起点
                    int preX = top.preX;
                    int preY = top.preY;
                    while (!stack.isEmpty()) {
                        top = stack.pop();
                        //只找最短路径的那条路
                        if (preX == top.x && preY == top.y) {
                            if (top.direction != null) {
                                sb.append(top.direction);
                            }
                            preX = top.preX;
                            preY = top.preY;
                        }

                    }
                    //反转字符串
                    return sb.reverse().toString();
                }
                // bfs,直接求出最短路径
                if (x >= 0 && x < row && y >= 0 && y < column && labyrinth[x][y] == 0 && visit[x][y] == 0) {
                    Node newNode = new Node(x, y, head.x, head.y, head.step + 1, d);
                    //将newNode添加到queue队列中
                    queue.offer(newNode);
                }
            }
        }
        return null;
    }
}

class Node {
    //当前坐标
    int x, y;
    //路径步数
    int step;
    //上一步的坐标
    int preX, preY;
    //方向
    String direction;

    Node(int x, int y, int preX, int preY, int step, String direction) {
        this.x = x;
        this.y = y;
        this.preX = preX;
        this.preY = preY;
        this.step = step;
        this.direction = direction;
    }

}

F_特别数的和

本题可以转换为String,再continue相加,也可以按照下面的方法

package _2019;

import java.util.Scanner;

/**
 * 小明对数位中含有 2、0、1、9 的数字很感兴趣(不包括前导 0),
 * 在 1 到 40 中这样的数包括 1、2、9、10 至 32、39 和 40,共 28 个,他们的和是 574。 请问,在 1 到 n 中,所有这样的数的和是多少?
 */
public class F_特别和的数 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int num = 0;
        for (int i = 1; i <= n; i++) {
            int b = i;
            while (b > 0) {
                int a = b % 10;
                if (a == 2 || a == 0 || a == 1 || a == 9) {
                    num += i;
                    break;
                }
                b = b / 10;
            }
        }
        System.out.println(num);

    }
}

G_外卖优先级

“饱了么”外卖系统中维护着 N 家外卖店,编号 1 ∼ N。每家外卖店都有 一个优先级,初始时 (0 时刻) 优先级都为 0。 每经过 1 个时间单位,如果外卖店没有订单,则优先级会减少 1,最低减 到 0;而如果外卖店有订单,则优先级不减反加,每有一单优先级加 2。 如果某家外卖店某时刻优先级大于 5,则会被系统加入优先缓存中;如果 优先级小于等于 3,则会被清除出优先缓存。 给定 T 时刻以内的 M 条订单信息,请你计算 T 时刻时有多少外卖店在优 先缓存中。
【输入格式】 第一行包含 3 个整数 N、M 和 T。 以下 M 行每行包含两个整数 ts 和 id,表示 ts 时刻编号 id 的外卖店收到 一个订单。
【输出格式】
输出一个整数代表答案。
【样例输入】 2 6 6 1 1 5 2 3 1 6 2 2 1 6 2
【样例输出】 1
【样例解释】 6 时刻时,1 号店优先级降到 3,被移除出优先缓存;2 号店优先级升到 6, 加入优先缓存。所以是有 1 家店 (2 号) 在优先缓存中。
【评测用例规模与约定】 对于 80% 的评测用例,1≤ N,M,T ≤10000。 对于所有评测用例,1≤ N,M,T ≤100000,1≤ts≤T,1≤id ≤ N。

利用一个二维数组存储每个订单的下单时刻和下单店铺

package _2019;

import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

public class G_外卖优先级 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        //set集合表示缓存中的外卖店铺
        Set set = new HashSet();
        //外卖店铺数
        int n = scanner.nextInt();
        //订单数量
        int m = scanner.nextInt();
        //下单时刻
        int t = scanner.nextInt();
        //每行表示一个订单,第一列表示下单时间,第二列表示下单店铺,为了更贴合实际,第0行和第0列废弃不用
        int otder[][] = new int[m+1][2+1];
        //下单店铺和下单时间都是从1开始
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= 2; j++)
                otder[i][j] = scanner.nextInt();
        }

        //店铺从1开始,所以变换成数组为 int[n+1]
        int[] yxj = new int[n + 1];

        //存储每个时刻该店铺是否有订单,若有则为1,没有则为默认0
        int[] sign = new int[n + 1];

        for (int i = 1; i <= t; i++) {
            for (int j = 1; j <= m; j++) {
                //此时刻有店铺有订单
                if (otder[j][1] == i) {
                    //表示该时刻,id为otder[j][2]的店铺有订单,后面不会进行优先级--
                    sign[otder[j][2]] = 1;
                    //此id的店铺优先级+2
                    yxj[otder[j][2]] += 2;

                    //set会自动去重,此处不用判断otder[j][2]是否存在于set集合中
                    if (yxj[otder[j][2]] > 5 ) {
                        set.add(otder[j][2]);
                    }
                }

            }

            for (int j = 1; j <= n; j++) {
                //没有订单且优先级大于0的店铺,优先级--
                if (sign[j] == 0 && yxj[j] > 0) {
                    yxj[j]--;
                }
                //如果某店铺优先级小于等于3,移出缓存,若缓存中本来就没有该店铺,自然不会移除
                if (yxj[j] <= 3) {
                    set.remove(j);
                }
            }

            //表示时刻的第一层循环结束,重置sign
            sign = new int[n + 1];

        }
        //set集合的长度即为缓存中的店铺数,因为set自动去重,同一个店铺不会存储多次
        System.out.println(set.size());
    }
}

H_人物相关性分析

小明正在分析一本小说中的人物相关性。他想知道在小说中 Alice 和 Bob有多少次同时出现。
更准确的说,小明定义 Alice 和 Bob“同时出现”的意思是:在小说文本中 Alice 和 Bob 之间不超过 K 个字符。
例如以下文本:
This is a story about Alice and Bob. Alice wants to send a private message to Bob.
假设 K = 20,则 Alice 和 Bob 同时出现了 2 次,分别是”Alice and Bob”和”Bob. Alice”。
前者 Alice 和 Bob 之间有 5 个字符,后者有 2 个字符。
注意:

Alice 和 Bob 是大小写敏感的, alice 或 bob 等并不计算在内。

Alice 和 Bob 应为单独的单词,前后可以有标点符号和空格,但是不能有字母。例如 Bobbi 並不算出现了 Bob。

【输入格式】
第一行包含一个整数 K。
第二行包含一行字符串,只包含大小写字母、标点符号和空格。长度不超过 1000000。

【输出格式】
输出一个整数,表示 Alice 和 Bob 同时出现的次数。

【样例输入】
20
This is a story about Alice and Bob. Alice wants to send a private message to Bob.
【样例输出】
2

此题利用滑动窗口算法,利用暴力破解枚举的话,时间超限,显示应该是时间超限60

因为刚开始学算法,只会暴力破解

package text;

import java.util.Scanner;

public class H {

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int K = input.nextInt();
        input.nextLine();
        String text = input.nextLine();
        //字符串分割,按照空格和.分割字符,若是(.空格)分割后为空字符串。正则表达式,空格后面有任何字符都拆分
        String[] words = text.split("\\s+|\\.");
        int[] wordsLength = new int[words.length];
        //将分割的字符串的长度值存储,避免三重循环中调用String.length();
        for (int i = 0; i < words.length; i++) {
            wordsLength[i] = words[i].length();
        }
        int num = 0;

        for (int i = 0; i < words.length; i++) {
            if (words[i].equals("Alice")) {
                for (int j = 0; j < words.length; j++) {
                    //初始sum就等于1,表示 Alice后面的那一个空格
                    int sum = 1;
                    if (words[j].equals("Bob")) {
                        //如果Bob出现再Alice之后
                        if (j>i){
                            for (int k = i + 1; k < j; k++) {
                                //每个单词的长度加单词后面的一个空格占据的长度
                                sum += wordsLength[k] + 1;
                            }
                        }else if (i>j){//Bob出现在Alice之前
                            for (int k = j+1;k < i ;k++){
                                sum += wordsLength[k] + 1;
                            }
                        }

                        if (sum <= K) {
                            num++;
                        }
                    }
                }
            }
        }
        System.out.println(num);
    }

}

后来又看懂了滑动窗口(双指针)算法

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class H_人物相关性分析_2 {
    /**
     * alice和bob两个集合分别都是用来存储对应人物在输入字符串中每次出现的下标
     * 使用List可以有序存储(有序表示存进去和取出来的顺序一样,可以按照下标直接get出来,不是字典序排序)
     */
    private static List<Integer> alice = new ArrayList<>();
    private static List<Integer> bob = new ArrayList<>();
    //输入k的值
    private static int K;
    //data的值为输入的那一串字符串
    private static String data = null;

    /**
     * 判断字符串的值
     * @param i 当前下标位置
     * @param num 3或者5,表示Bob和Alice单词截取长度
     * @param peopleSuf 用来做比较,如Bob传入"ob",Alice传入"lice"
     * @param isAlice  用来判断是添加到Alice集合中还是Bob数组中
     * @return
     */
    public static boolean check(int i, int num, String peopleSuf, boolean isAlice) {
        // 看前面,若前面有字母,则表示不是Bob或者Alice,直接排除,如 isBob等
        if (i - 1 >= 0) {
            int preChar = data.charAt(i - 1);
            //A的ASCII码是65,Z的是90  a的是97,z的是122
            if ((preChar >= 65 && preChar <= 90) || (preChar >= 97 && preChar <= 122)) {
                // 如果是字母,就直接返回
                return false;
            }
        }
        //用来存储临时字符串,方便与peopleSuf作比较
        String nextFourChar;
        // 从当前字符开始算,看后第 num 个字符是否为字母,如Alice,第i个是A,往后数5个,如为Alices,则charAt(i + num)是s,不符合条件
        if (i + num < data.length()) {
            int nextFifthChar = data.charAt(i + num);
            if ((nextFifthChar >= 65 && nextFifthChar <= 90) || (nextFifthChar >= 97 && nextFifthChar <= 122)) {
                // 如果是字母,就直接返回
                return false;
            }
            //截取字符串,含头不含尾,即新的字符串是从 i+1 到 i+num-1
            nextFourChar = data.substring(i + 1, i + num);
        } else {
            // 右边没有字符了,直接取到最后
            //data.substring(i + 1) 表示去掉前i+1个字符,返回一个新的字符串
            nextFourChar = data.substring(i + 1);
        }
        //判断截取的字符串是不是参数peopleSuf
        if (nextFourChar.equals(peopleSuf)) {
            // 是Alice,记录此时的i索引
            if (isAlice) {
                alice.add(i);
            } else {
                bob.add(i);
            }
            return true;
        }

        return false;
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int K =input.nextInt();
        // input.nextLine();表示吃掉第一行输入过后的回车,或者直接将这行注释的上下两行改为一行,利用nextLine不用吃回车,但需要转换:
        //int k = Integer.parseInt(input.nextLine());
        input.nextLine();
        data = input.nextLine();
        input.close();

        // 1、先扫描一遍字符串,将其中的Alice和Bob出现的所有索引都记录下来
        int index = 0;
        while (index < data.length()) {
            //如果当前下标表示的字符为 A
            if (data.charAt(index) == 'A') {
                //判断字符A前面是否还有字符,并判断它后面的四个字符是否是lice
                if (check(index, 5, "lice", true)) {
                    index += 5;
                } else {
                    index++;
                }
            } else if (data.charAt(index) == 'B') {
                if (check(index, 3, "ob", false)) {
                    index += 3;
                } else {
                    index++;
                }
            } else {
                index++;
            }
        }


        // 2、遍历每一个Alice,通过双指针去实现在每一个Alice[alice[i] - K - 3, alice[i] + K + 5]范围内有多少个,依次做累加
        // 定义两个指针,初始都为0,两者都代表当前是的第几个Bob,只不过这里第1个Bob,下标是0
        // ans用于累加,必须用long类型,int类型不够大
        long ans = 0;
        int left = 0, right = 0; // left和right是两个集合的下标,而取出来的也是下标,不过取出来的下标是在输入字符串中的下标
        for (int i = 0; i < alice.size(); i++) {
            /*
                外层循环是遍历每一个Alice,取出其在data字符串中的位置,
                内存循环每次取Bob的下标跟 alice.get(i) - K - 3 和 alice.get(i) + K + 5 进行比较,
                而循环内部是找出该Alice左边K范围内的Bob和和右边K范围内的Bob之和
             */
            // 以下两个while是用来确定当前Alice能够与Bob同时出现的最大范围,也就是left与right之间的距离
            // 先固定住左边界,然后移动右边界
            while (left < bob.size() && bob.get(left) < alice.get(i) - K - 3) {
                left++;
            }
            // 注意:这里的 = 一定要算在内,
            // 与left不同,这里right++很有可能会直接超过[alice[i] - K - 3, alice[i] + K + 5]的右边界,
            // 则需要加上等于号,避免漏掉数据,后续再将right-1就好
            // 循环结束后 bob.get(right) > alice.get(i) + K + 5
            while (right < bob.size() && bob.get(right) <= alice.get(i) + K + 5) {
                right++;
            }
            // 此时 bob.get(right) > alice.get(i) + K + 5 所以这里是要算right - 1与left之间有多少个数
            // 包含两个边界,如2~3,表示的是 (3-2)+1个数,需要加1
            if (right-1 - left+1  > 0) {
                // 判断距离是否大于零,若大于0,则表示当前的Alice对应的这个范围有与她同时出现的Bob
                ans += right-1  - left +1;
            }
        }
        System.out.println(ans);
    }
}

2020

B_纪念日

2020 年 7 月 1 日是A组织 成立 99 周年纪念日。
A组织成立于 1921 年 7 月 23 日。
请问从 1921 年 7 月 23 日中午 12 时到 2020 年 7 月 1 日中午 12 时一共包
含多少分钟?
    public static void main(String[] args) {
        //SimpleDateFormat类用以格式化时间
        SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd");
        try {
            //SimpleDateFormat.parse将符合格式的字符串转换为Date格式
            Date date1 = s.parse("1921-7-23");
            Date date2 = s.parse("2020-7-1");
            //Date.getTIme 返回自从GMT 1970-01-01 00:00:00到此date对象上时间的毫秒数
            int a = (int)((date2.getTime()-date1.getTime()) / (1000*60));
            System.out.println(a);
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }

C_合并检测

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

/**
 * 很像数学问题, 设共有100个人,则患者有1人,共分为 [100/k] (向上取整)个组,需要[100/k]+(0.01*m)*k + m%100 个试剂(每组一个试剂,其中有一个组需要全员试剂)
 */
public class C_合并检测 {
    public static void main(String[] args) {
        System.out.println("请输入测试数据m");
        Scanner scanner = new Scanner(System.in);
        double m = scanner.nextInt();
        int min = Integer.MAX_VALUE;
        //最少的k个数
        double kmin = Double.MAX_VALUE;
        int temp = 0;
        for (double k =1;k<=m;k++){
            //Math.ceil表示向上取整
            temp = (int) (Math.ceil(m / k) + (0.01 * m) * k);
            if (temp<min){
                min = temp;
                kmin = k;
            }
        }

        System.out.println(kmin);
    }

}

D_分配口罩

某市市长获得了若干批口罩,给定每批口罩的数量,
市长要把口罩分配给市内的 2 所医院,由于物流限制,每一批口罩只能全部分
市长希望 2 所医院获得的口罩总数之差越小越好。 请你计算这个差最小是多
各批口罩数量
9090400
8499400
5926800
8547000
4958200
4422600
5751200
4175600
6309600
5865200
6604400
4635000
10663400
8087200
4554000
public class D_分配口罩 {

    public static long res = Long.MAX_VALUE;

    public static long num[]={9090400, 8499400, 5926800, 8547000, 4958200,
            4422600, 5751200, 4175600, 6309600, 5865200,
            6604400, 4635000, 10663400, 8087200, 4554000
    };

    public static void main(String[] args) {
        dfs(0,0,0);
        System.out.println(res);
    }
    public static void dfs(int k,long sum1,long sum2){
        if (k==15){
            res = res < Math.abs(sum1-sum2)? res : Math.abs(sum1-sum2);
            return;
        }
        dfs(k+1,sum1+num[k],sum2);
        dfs(k+1,sum1,sum2+num[k]);
    }
}

E_斐波那锲最大公约数

【问题描述】
斐波那契数列满足 F1 = F2 = 1,从 F3 开始有 Fn = Fn 1 + Fn 2。请你计算
GCD(F2020, F520),其中 GCD(A, B) 表示 A 和 B 的最大公约数。
【答案提交】
这是一道结果填空题,你只需要算出结果后提交即可。本题的结果为一个
整数,在提交答案时只填写这个整数,填写多余的内容将无法得分

package _2020;

import java.math.BigInteger;

public class E_斐波那锲最大公约数 {
    public static void main(String[] args) {
        BigInteger num1 = fbnq(2020);
        BigInteger num2 = fbnq(520);
        //自己写的方法
       // BigInteger res = gcd(num1,num2);
        //BigInteger封装的方法
        BigInteger res = num1.gcd(num2);
        System.out.println(res);
    }
    public static BigInteger fbnq(int num){
        //1 1 2 3 5 8 13
        BigInteger a = BigInteger.ONE,b = BigInteger.ONE;
        BigInteger c = BigInteger.ZERO;
        for (int i = 3;i<=num;i++){
            c = a.add(b);
            a = b;
            b = c;
        }
        return c;
    }

/*    public static BigInteger gcd(BigInteger bigInteger1,BigInteger bigInteger2){
        if (String.valueOf(bigInteger2) == "0"){
            return bigInteger1;
        }
        return gcd(bigInteger2,bigInteger1.mod(bigInteger2));
    }*/
}

F_分类计数

输入一个字符串,请输出这个字符串包含多少个大写字母,多少个小写字母,多少个数字。
【输入格式】
输入一行包含一个字符串。
【输出格式】
输出三行,每行一个整数,分别表示大写字母、小写字母和数字的个数。
【样例输入】
1+a=Aab
【样例输出】
1
3
1
【评测用例规模与约定】
对于所有评测用例,字符串由可见字符组成,长度不超过 100。
public class F_分类计数 {
    /*    //利用ASCII码
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            String data = scanner.nextLine();
            int temp = 0;
            int snum = 0,bnum = 0,num = 0;
            for (int i = 0;i<data.length();i++){
                temp = data.charAt(i);
                if (temp>=48 && temp<=57){
                    num++;
                }else if (temp >=65 && temp <=90){
                    bnum++;
                }else if (temp >=97 && temp <=122){
                    snum++;
                }
            }
            System.out.println(bnum);
            System.out.println(snum);
            System.out.println(num);
        }*/
    //利用Character包装类里的方法
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String data = scanner.nextLine();
        int a = 0,b=0,c=0;
        for (int i = 0;i<data.length();i++){
            if (Character.isDigit(data.charAt(i))){
                a++;
            } else if (Character.isUpperCase(data.charAt(i))) {
                b++;
            } else if (Character.isLowerCase(data.charAt(i))) {
                c++;
            }
        }
        System.out.println(b);
        System.out.println(c);
        System.out.println(a);
    }
}

G_八次求和

【问题描述】
给定正整数 n, 求 1^8 + 2^8 +···+ n^8 mod 123456789 。其中 mod 表示取余。
【输入格式】
输入的第一行包含一个整数 n。
【输出格式】
输出一行,包含一个整数,表示答案。
【样例输入】
2
【样例输出】
257
【样例输入】
987654
【样例输出】
43636805
【评测用例规模与约定】
对于 20% 的评测用例,1≤n≤20。
对于 60% 的评测用例,1≤n≤1000。
对于所有评测用例,1≤n≤1000000。

本题利用BigInteger中的pow写出,如用Math中的会溢出

package _2020;

import java.math.BigInteger;
import java.util.Scanner;

public class G_八次求和 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        BigInteger sum = BigInteger.ZERO;
        int n = scanner.nextInt();
        for (int i = 1; i <= n; i++) {
            sum = sum.add(new BigInteger(i+"").pow(8));
        }
        System.out.println(sum);
    }
}

H_字符串编码

问题描述
小明发明了一种给由全大写字母组成的字符串编码的方法。
对于每一个大写字母,小明将它转换成它在 26 个英文字母中序号
这样一个字符串就能被转化成一个数字序列:比如 ABCXYZ →
现在给定一个转换后的数字序列,小明想还原出原本的字符串。
当然这样的还原有可能存在多个符合条件的字符串。
小明希望找出其中字典序最大的字符串。
输入格式
一个数字序列。
输出格式
一个只包含大写字母的字符串,代表答案
样例输入
123242526
样例输出
LCXYZ
评测用例规模与约定
对于 20% 的评测用例,输入的长度不超过 20。
对于所有评测用例,输入的长度不超过 200000。
public class H_字符串编码 {
    //前面添加0的作用是,使 arr[i]对应相应的字符,如 1对A,2对B
    public static char[] arr = {
            '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'
    };

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String string = scanner.next();
        String res = "";
        for (int i = 0; i < string.length(); i++) {
            int temp = string.charAt(i) - '0';
            if (i+1 < string.length()){
                int x = temp*10 + (string.charAt(i+1)-'0');
                if ( x<= 26){
                    res+= arr[x];
                    i++;
                }else {
                    res+= arr[string.charAt(i)-'0'];
                }
            }else {
                res+= arr[string.charAt(i)-'0'];
            }

        }
        System.out.println(res);

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值