蓝桥杯第十二届真题解析

目录

前言

考试技巧

真题解析        

第一题 (ASC)

第二题 (卡片)

第三题 (直线)

第四题 (货物摆放)

第五题 (路径)

第六题 (时间显示)

第七题 (最少砝码)

第八题 (杨辉三角形)

第九题 (双向排序)

第十题 (括号序列)

总结


前言

        蓝桥杯第十三届省赛在4月9号开始,按照以往惯例,基本填空题4道,编程题2-3道,省一基本就稳了。

        蓝桥杯省赛考的比较基础,除了最后一题,其他基本都是简单或者中等题,我们不需要所有题都做出来,只需要保证自己会做的不错,那么省一基本没有什么问题。下面是我上一次参加省赛的奖状

蓝桥杯第十二届真题解析_第1张图片


考试技巧

        根据我自己参加比赛的经历,省赛整体难度较低,大部分题目都可以暴力得部分分数,对于省赛,我们需要重点复习以下知识点

  1. 对于java组,我们必须要能够熟练掌握BigInteger,BigDecimal这2个类必须掌握,如果不会,马上去学习,这2个类可以实现大数的运算,具有奇效!!!
  2. 在省赛中,基本每次都有关于时间的题目,所以,对于时间的api,我们也必须要能够掌握,在java中,例如Data类,Calendar,LocalDate,LocalDateTime这几个类也必须掌握。
  3. 在省赛中数据结构肯定会考,基本的DFS,BFS必须要会,树的遍历,特点也要熟悉,对于图的几种基本算法也要学一下,如最短路径
  4. 上面的3点是必须掌握的,下面就是提升类的,蓝桥杯在以前一直被称为暴力杯,这是因为在前几届的蓝桥杯确实都是暴力解题,但是现在开始提升难度了,在上一届dp(动态规划)的题就开始增多了,如果想拿个好成绩,别犹豫,马上去刷动态规划的题目吧!!
  5. 接下来就是字符串相关的,这个也考的十分的多,建议去leetcode看一下字符串专栏,大致了解下常见的算法,在比赛时遇到最起码有个方向
  6. 下一点,全排列,不知道大家会不会,由于java没有现成的函数,所以建议现在自己写下函数,这个用到的几率很大
  7. 这点很重要,认真读题,认真读题,认真读题,题目建议多读几遍,彻底弄清楚意思后再开始想解题思路
  8. 对于难题,10分钟没有思路,马上跳过,先把自己能做的全部做了再思考,蓝桥杯的难度一般都是随题目号数递增的,也就是越到后面越难
  9. 做题,如果不是特别有经验,建议第一种解法都从暴力开始,然后进行优化
  10. 最后一点,蓝桥杯的测试案列特别少,你写完代码后可能觉得自己做对了,测试用例也对,然后就直接提交了,比赛结束后才发现自己没有考虑周全,这时已经为时已晚,我们在写完代码后,建议至少编写5个测试用例及以上,对代码进行测试,并且测试用例要数值比较大或者比较刁钻。

        总之,蓝桥杯省赛难度不大,只要学过基本的数据结构和算法,省一基本没问题,省赛的差距就是细心,最后再重复三次,细心,细心,细心


真题解析        

        下面对上一届的题目进行讲解说明,也就是第十二届java B组


第一题 (ASC)

蓝桥杯第十二届真题解析_第2张图片

        这道题送分题,不解释,直接给出答案,76


第二题 (卡片)

蓝桥杯第十二届真题解析_第3张图片

         这道题就是暴力模拟,我们定义10大小的数组代表0-9,每个值都是2021,然后循环判断,如果数组值都不为0,那么就继续。我们对循环的数字依次得到每个位数,然后再数组中进行相减就行,可能描述有点模糊,下面直接看代码。

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] nums = new int[10];
        Arrays.fill(nums, 2021);
        int ans = 1;
        //设置标记,是否退出循环
        boolean flag = false;
        while (true) {
            //对于每一个num,通过字符串方式获取每一个数字
            for (char num : (ans + "").toCharArray()) {
                //将对于位置的数字-1,看是否为0
                if (--nums[num - '0'] == 0) {
                    flag = true;
                    break;
                }
            }
            if (flag) break;
            ans++;
        }
        System.out.println(ans);
    }

}

        答案为:3181


第三题 (直线)

蓝桥杯第十二届真题解析_第4张图片

        这道题也简单,需要注意的就是浮点数的问题。y=kx+b,思路就是算出所有的直线的斜率k和b,然后放入set去重就行,这里需要重点注意精度问题,注意浮点数误差,我是直接使用java的BigDecimal解决的

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashSet;

public class Main {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet<>();
        for (int i = 0; i < 20; i++) {
            for (int j = 0; j < 21; j++) {
                for (int m = i + 1; m < 20; m++) {
                    for (int n = 0; n < 21; n++) {
                        // y = kx + b通过2个点算出 b和k,然后返回b_k字符串,存入set
                        String bk = getBK(i, j, m, n);
                        hashSet.add(bk);
                    }
                }
            }
        }
        //这里加20是因为有20条直线没有斜率
        System.out.println(hashSet.size() + 20);
    }

    public static String getBK(double x1, double y1, double x2, double y2) {
        // k保留小数点后50位
        BigDecimal k = new BigDecimal(y1 - y2).divide(new BigDecimal(x1 - x2), 50, RoundingMode.FLOOR);
        BigDecimal b = new BigDecimal(y1).subtract(new BigDecimal(x1).multiply(k));
        // b和k都保留15位小数
        b = b.setScale(15, RoundingMode.FLOOR);
        k = k.setScale(15, RoundingMode.FLOOR);
        return b + "_" + k;
    }

}

        答案为:40257


第四题 (货物摆放)

蓝桥杯第十二届真题解析_第5张图片

        这道题直接暴力解决即可,没什么难度,算出n的所有因数,然后循环判断就行

import java.util.HashSet;

public class Main {
    public static void main(String[] args) {
        long num = 2021041820210418L;
        HashSet hashSet = new HashSet<>();
        //将num所有因数加入集合
        for (long i = 1; i <= Math.sqrt(num); i++) {
            if (num % i == 0){
                hashSet.add(i);
                hashSet.add(num / i);
            }
        }
        long ans = 0;
        //暴力对所有因数进行循环
        for (Long x : hashSet) {
            for (Long y : hashSet) {
                for (Long z : hashSet) {
                    if (x * y * z == num)ans++;
                }
            }
        }
        System.out.println(ans);
    }

}

         答案:2430


第五题 (路径)

蓝桥杯第十二届真题解析_第6张图片

        这道题就是想考察图里面的最短路径问题,但是我们可以转化为dp来做,首先求出所有点到后面21个的距离,存入数组,然后进行dp即可,dp[i] = min(dp[i],dp[i-k][k]) k范围就是1-21 

public class Main {
    public static void main(String[] args) {
        long[] dp = new long[2022];
        //存放当前点到后面21个点的距离,下标1开始
        long[][] dis = new long[2022][22];
        for (int i = 1; i < 2022; i++) {
            for (int j = 1; j < 22; j++) {
                if (i + j > 2021) break;
                dis[i][j] = getDis(i, i + j);
            }
        }
        for (int i = 1; i < 2022; i++) {
            long min = Long.MAX_VALUE;
            //求出到当前点的最小值
            for (int j = 1; j <= 21; j++) {
                if (i - j <= 0) break;
                min = Math.min(min, dp[i - j] + dis[i - j][j]);
            }
            if (min != Long.MAX_VALUE) dp[i] = min;
        }
        System.out.println(dp[dp.length - 1]);
    }

    public static long getDis(long a, long b) {
        return a * b / gcd(a, b);
    }

    public static long gcd(long a, long b) {
        return a % b == 0 ? b : gcd(b, a % b);
    }
}

        答案:10266837


第六题 (时间显示)

蓝桥杯第十二届真题解析_第7张图片

        送分题,不解释,直接给出代码,注意输出格式,建议使用printf

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        long time = new Scanner(System.in).nextLong();
        long h = (time / 1000 / 60 / 60) % 24;
        long m = (time / 1000 / 60) % 60;
        long s = (time / 1000) % 60;
        System.out.printf("%02d:%02d:%02d", h, m, s);
    }
}

第七题 (最少砝码)

蓝桥杯第十二届真题解析_第8张图片

蓝桥杯第十二届真题解析_第9张图片

         这道题怎么说呢,可以动态规划,可以暴力模拟,但是最优解法是平衡3进制模拟,不知道大家听说过3进制没有,这里使用3进制来做,砝码3种状态刚好对应,放左边,放右边,不放,原理就是3进制,两两组合,-1,0,1,组合后可以表示不重复的9个数

三进制 十进制
-1 -1
0 0
1 1
-1 -1 -4
-1 0 -3
-1 1 -2
1 -1 2
1 0 3
1 1 4

     三进制数可以表示所有    [-\frac{3^n-1}{2},\frac{3^n-1}{2}](n\in Z)的数,又因为题目需要满足条件为\frac{3^n-1}{2}\geq N,通过计算,可以求出n≥log3​(2N+1),所以我们需要的砝码重量就是3^{x},x>=0,下面就可以很容易的写代码了,我说的可能不是很清楚,可以看下下面的解释,如果不理解,直接跳过也没关系,暴力,dp都能得大部分分。

举个例子,平衡3进制的1和3,也就是 1 和 10这2个数就可以表示到11,也就是可以表示到4

十进制1,3,9,平衡三进制表示为 1 10 100,
这3个数通过加减运算就可以表示到-1-1-1到111的所有范围,也就是 (-14,14)

十进制1,3,9,27,平衡三进制表示为 1 10 100 1000,
这4个数就可以表示 -1-1-1-1到1111的所有范围也就是(-40,40)

        如果还不明白,可以参考 对称三进制数详解 

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        long n = new Scanner(System.in).nextLong();
        int count = 1;
        int i;
        for (i = 1; count < n; i++) {
            count += Math.pow(3, i);
        }
        System.out.println(i);
    }
}

第八题 (杨辉三角形)

蓝桥杯第十二届真题解析_第10张图片

蓝桥杯第十二届真题解析_第11张图片

         这道题涉及到数学推导,下面给出2种解放,第一种暴力,可以得一半的分

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        int n = new Scanner(System.in).nextInt();
        if (n == 1) {
            System.out.println(1);
            return;
        }
        //动态dp,2行进行切换
        int[][] dp = new int[2][100000];
        long count = 1;
        dp[0][1] = 1;
        int i = 1, j = 1;
        //当前层数
        for (int layer = 2; ; layer++) {
            //每层的数量和当前层数相同
            for (int k = 0; k < layer; k++) {
                //简单dp
                if (layer % 2 == 0) dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1];
                else dp[i][j] = dp[i + 1][j] + dp[i + 1][j - 1];
                count++;
                if (dp[i][j++] == n) {
                    System.out.println(count);
                    return;
                }
            }
            //根据层数判断是从0开始还是1开始
            i = layer % 2 != 0 ? 1 : 0;
            j = 1;
        }
    }
}

蓝桥杯第十二届真题解析_第12张图片

         如果想要得全部分,那么就要进行数学推导,从数学的方面来考虑,由于过程比较复杂,篇幅有限,直接给出推导的链接,很详细,可以自己进行查看 数学推导 得分为100

蓝桥杯第十二届真题解析_第13张图片


第九题 (双向排序)

蓝桥杯第十二届真题解析_第14张图片

蓝桥杯第十二届真题解析_第15张图片

蓝桥杯第十二届真题解析_第16张图片

         这道题也是用到数学,但是我们暴力解决可以获得60分,也还行,下面给出暴力解法的代码和数学推导的链接

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        Integer[] arr = new Integer[n+1];
        for (int i = 1; i < arr.length; i++) {
            arr[i] = i;
        }
        for (int i = 0; i < m; i++) {
            int num1 = scanner.nextInt();
            int num2 = scanner.nextInt();
            //直接调用api
            if (num1 == 0){
                Arrays.sort(arr, 1, num2+1, (o1, o2) -> o2-o1);
            }else {
                Arrays.sort(arr, num2, n+1);
            }
        }
        for (int i = 1; i <= n; i++) {
            System.out.print(arr[i]+" ");
        }
    }
}

蓝桥杯第十二届真题解析_第17张图片

         由于博客已经很长了,数学推导不做结束,给出链接自行查看即可 数学推导,这个就可以得到100分

蓝桥杯第十二届真题解析_第18张图片


第十题 (括号序列)

蓝桥杯第十二届真题解析_第19张图片

蓝桥杯第十二届真题解析_第20张图片

         最后一题很难,一般都是留给打 ACM 的做的,如果不是打acm的直接跳过,对成绩没有任何影响,这道题就不进行解释了,如果感兴趣,参考 括号序列详解,这位大佬给出了详细的解法,可以参考一下

蓝桥杯第十二届真题解析_第21张图片


总结

        蓝桥杯难度主要集中在后面几题,最后一题直接放弃,我们如果没有思路,那么就使用暴力即可,能得多少分算多少,大家要相信,你觉得难,其他人也觉得难,蓝桥杯省赛,填空题4道,编程题3道,省一肯定没问题。

        最后再说一点,省赛不难,最重要的就是认真读题,认真读题,认真读题,细心,细心,再细心。祝愿大家都能在蓝桥杯中取得好成绩!!!

你可能感兴趣的:(算法,蓝桥杯,算法,java)