第十三届蓝桥杯JAVAB组部分题解

  • 非常nice,去年C++国赛填空题我全错喜提国三,今年javaB组填空题依旧全错,稳定发力(bushi

试题 A: 星期计算

  • 已知今天是星期六,请问 2 0 22 20^{22} 2022 天后是星期几?

  • 答案:7

python跑出来结果为

>>> (20 ** 22) % 7 + 6
7

不好意思我是sb,第一遍题解刚刚写错了

试题 B:

  • [2022, 2022222022]中先单调不减,后单调不增的回文数的数量
  • 答案:3138

错误答案:120101

我个笨比题目没读完,读成回文数的数量了

试题 C: 字符统计

  • 题意:给定一个仅由大写字母组成的字符串,求出现次数最多的字母

  • 26个桶cnt[]计数一下每个字母出现的数量,再for一遍求出最大的桶的容量ans,然后最后for一遍看有哪些桶的容量等于ans输出答案

import java.util.Scanner;

public class C {
    static int cnt[] = new int[30];
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.next();
        int len = s.length();
        char now;
        for(int i = 0; i < len; i ++ )
        {
            now = s.charAt(i);
            cnt[(int)(now - 'A')] ++;
        }
        int ans = -1;
        for (int i = 0; i < 26; i++) {
            if(cnt[i] > ans)
                ans = cnt[i];
        }
        for (int i = 0; i < 26; i++) {
            if(cnt[i] == ans)
            {
                now = (char)(i + 'A');
                System.out.print(now);
            }
        }
//        BABBACAC
    }
}

试题 D: 最少刷题数

  • 题意:n个人,每个人该学期的刷题数量为a[i],问对于每一个人,他最少需要再刷多少题,才能使得题数比他大的人不超过题数比他少的人。其中 1 ≤ n ≤ 1 0 6 1\le n \le 10^6 1n106

  • 这题我卡了很久,也不知道我考场的时候在犯什么sb

  • 此处先约定,下标从0开始,即0~(n-1)。很显然的一个思路就是先排序一遍,然后根据中位数a[n / 2 + 1 - 1],即a[n / 2]来判断。我们约定u = a[n / 2],注意,当你的成绩等于中位数u(向上取整的那个)的时候不一定满足条件,你可能还需要再刷题,比如4 4 4 4 5,比中位数4大的数有1个,比它小的有0

  • 但是你当你的目标达到u + 1的时候是一定满足条件的

  • 我们通过另一个数组b来保存原来的a数组

  • 所以我们得特判b[i] = u的情况,统计整个数组中比u大的数的数量mx,比u小的数量mi

  1. 对于b[i] == u的这些人,我们讨论它的目标设置的题数
    1. 如果mx <= mi的话,则你不刷题也能满足条件,即目标题数为u
    2. 反之,则说明这些人需要再刷1题,即目标题数为u + 1
  2. 对于b[i] < u的这些人
    1. 如果mx <= mi - 1,则这些人的目标题数为u题。因为这个人从一个比u小的数变为u,那么mi也会减小1,所以mx <= mi - 1即代表变为u后满足条件,目标题数为u
    2. 反之,这些人的题数必须定为u + 1
  3. 对于b[i] > u的这些人,不需要刷任何题目也能满足条件
  • 我考场的时候大概就是这样的写的,一开始没有梳理清楚,以至于我非常乱,写完删又写又改的,这种题目应该先想清楚再写
import java.util.Arrays;
import java.util.Scanner;

public class D {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int a[] = new int[n];
        int b[] = new int[n];
        for (int i = 0; i < n; i++) {
            a[i] = sc.nextInt();
            b[i] = a[i];
        }
        if (n == 1) {
            System.out.print(0);
            return;
        }
        Arrays.sort(a);
        int u = a[n / 2];
        int lessAns, equAns;
        int mi = 0, mx = 0;
        for (int i = 0; i < n; i++) {
            if (b[i] < u)
                mi++;
            if (b[i] > u)
                mx++;
        }
        if (mx <= mi) {//==u 的为0
            equAns = 0;
        } else {
            equAns = 1;
        }
        if (mx <= mi - 1) { // < u 的达到u即是答案
            lessAns = u;
        } else {
            lessAns = u + 1;
        }
        for (int i = 0; i < n; i++) {
            if (i > 0) {
                System.out.print(' ');
            }
            if (b[i] > u) {
                System.out.print(0);
            } else if (b[i] < u) {
                System.out.print(lessAns - b[i]);
            } else {
                System.out.print(equAns);
            }
        }
    }
}

试题 E: 求阶乘

  • 题意:n!尾数恰好有k个零,求最小的n,若n不存在,则输出-1。其中 1 ≤ k ≤ 1 0 18 1\le k \le10^{18} 1k1018
  • 考虑因数分解,只有2/5两个质因数可以造出0,但是2的数量远远大于5的数量,所以我们只需要统计5的数量
  • 可以发现因子5是每5个加1,每25个加2,每125个加3……每隔5 ^ ii,最后贡献和为k的时候即是答案。这样我可以发现525的贡献会重复掉,故我们可以像叠积木一样计算,先把5的地基打上一层为n / 5,再打上25的贡献为n / 25,以此类推,最后可以算出累加和now
  • 我们可以发现,有单调性,n越大,后面跟着的0越多,区间满足单调性(二段性,前半段零的数量比k少,后半段比k多),故可以二分
  • 但是注意二分边界不能设置r = 1e18需要设r = 9e18(考场上我是写这个数字的,但是实际上只需要5e18即可),因为1e18的阶乘后面的0的数量不到1e18
  • 注意二分出来的答案,如果now = k不一定是最小的答案,需要最大的小于它的5的倍数
  • 我考场的代码如下:
import java.util.Scanner;

public class Main {
    final static long f[] = new long[]{1L, 5L, 25L, 125L, 625L, 3125L, 15625L, 78125L, 390625L, 1953125L, 9765625L, 48828125L, 244140625L, 1220703125L, 6103515625L, 30517578125L, 152587890625L, 762939453125L, 3814697265625L, 19073486328125L, 95367431640625L, 476837158203125L, 2384185791015625L, 11920928955078125L, 59604644775390625L, 298023223876953125L, 298023223876953125L * 5L};
    public static long check(long mid)
    {
        long res = 0;
        for(int i = 1; i < f.length; i ++)
        {
            res += mid / f[i];
        }
        return res;
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        long num = sc.nextLong();
//        System.out.println(check((long)9e18) /(long)1e18);
//        System.out.println(Long.MAX_VALUE);
//        System.out.println(f[f.length - 1] / (long)(1e18));
        long l = 1, r = (long)9e18;
        long mid;
        long now;
        while(l < r)
        {
            mid = (l + r) >> 1;
            now = check(mid);
            if(now < num)
            {//说明需要再增加
                l = mid + 1;
            }
            else
            {
                r = mid;
            }
        }
        if(check(r) == num)
            System.out.print(r);
        else
            System.out.print(-1);
    }
}

试题 F: 最大子矩阵

  • 给定一个n * m的矩阵,求解满足矩阵内最大值与最小值的差值不超过limit的最大面积的矩阵
  • 一开始觉得是单调栈,但是考场时间不够了,没时间细想,于是就直接写了一个四维的dp
  • 暴力做法如下,大致能拿50%的分数
import java.util.Scanner;

public class F {
    static int n, m;
    static int limit;
    //F题
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        m = sc.nextInt();
        int a[][] = new int[n][m];
        for (int i = 0; i < n; i++) {
            a[i] = new int[m];
            for (int j = 0; j < m; j++) {
                a[i][j] = sc.nextInt();
            }
        }
        int dp[][][][] = new int[n][m][n][m];
        int dp2[][][][] = new int[n][m][n][m];

        limit = sc.nextInt();
        for (int lx = 0; lx < n; lx++) {
            dp[lx] = new int[m][n][m];
            dp2[lx] = new int[m][n][m];
            for (int ly = 0; ly < m; ly++) {
                dp[lx][ly] = new int[n][m];
                dp2[lx][ly] = new int[n][m];
                for (int rx = lx; rx < n; rx++) {
                    dp[lx][ly][rx] = new int[m];
                    dp2[lx][ly][rx] = new int[m];
                    if (lx != rx) {
                        dp[lx][ly][rx][ly] = Math.max(dp[lx][ly][rx - 1][ly], a[rx][ly]);

                        dp2[lx][ly][rx][ly] = Math.min(dp2[lx][ly][rx - 1][ly], a[rx][ly]);

                        for (int ry = ly + 1; ry < m; ry++) {
                            dp[lx][ly][rx][ry] = Math.max(a[rx][ry], dp[lx][ly][rx][ry - 1]);
                            dp[lx][ly][rx][ry] = Math.max(dp[lx][ly][rx][ry], dp[lx][ly][rx - 1][ry]);

                            dp2[lx][ly][rx][ry] = Math.min(a[rx][ry], dp2[lx][ly][rx][ry - 1]);
                            dp2[lx][ly][rx][ry] = Math.min(dp2[lx][ly][rx][ry], dp2[lx][ly][rx - 1][ry]);
//                            System.out.println(lx + " " + ly + " " + rx + " " + ry + " : " + dp[lx][ly][rx][ry]);
                        }
                    } else {//lx == rx

                        dp[lx][ly][rx][ly] = a[rx][ly];
                        dp2[lx][ly][rx][ly] = a[rx][ly];
                        for (int ry = ly + 1; ry < m; ry++) {
                            dp[lx][ly][rx][ry] = Math.max(a[rx][ry], dp[lx][ly][rx][ry - 1]);

                            dp2[lx][ly][rx][ry] = Math.min(a[rx][ry], dp2[lx][ly][rx][ry - 1]);
//                            System.out.println(lx + " " + ly + " " + rx + " " + ry + " : " + dp[lx][ly][rx][ry]);
                        }
                    }
                }
            }
        }
        int sx, sy;
        int ans = Integer.MIN_VALUE;
        for (int lx = 0; lx < n; lx++) {
            for (int ly = 0; ly < m; ly++) {
                for (int rx = lx; rx < n; rx++) {
                    for (int ry = ly; ry < m; ry++) {
                        if(dp[lx][ly][rx][ry] - dp2[lx][ly][rx][ry] <= limit)
                        {
                            sx = rx - lx + 1;
                            sy = ry - ly + 1;
                            ans = Math.max(ans, sx * sy);
                        }
                    }
                }
            }
        }
        System.out.print(ans);
    }
}

试题 G: 数组切分

  • 将一个由1~n的排序划分为若干个连续的子数组,且每一段都是连续的自然数的方案数。其中 1 ≤ n ≤ 1 0 4 1\le n \le 10^4 1n104

  • 第一反应是dp,但是前面编程题卡太久了,没时间细想了,于是写了暴搜,大概拿了30%的分数。

import java.util.Scanner;

public class Main {
    final static long md = (long)(1e9 + 7);
    static int a[] = new int [30];
    static int n;
    static long ans = 0;
    static boolean used[] = new boolean[30];
    static boolean vis[] = new boolean[30];
    public static void dfs(int head, int h)
    {
        if(h == n + 1)
        {
            if(head == h)
            {
                ans = (ans + 1) % md;
            }
            return ;
        }
        dfs(head, h + 1);
        //继续向下加
        int mx = Integer.MIN_VALUE;
        int mi = Integer.MAX_VALUE;
        for(int i = 1; i <= n; i ++)
        {
            vis[i] = false;
        }
        for(int i = head; i <= h; i ++ )
        {
            mi = Math.min(a[i], mi);
            mx = Math.max(a[i], mx);
            vis[a[i]] = true;
        }
        for (int i = mi; i <= mx ; i++) {
            if(!vis[i])
            {
                return ;
            }
        }
        dfs(h + 1, h + 1);
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        if(n > 20)
        {
            return ;
        }
        for (int i = 1; i <= n; i++) {
            a[i] = sc.nextInt();
        }
        dfs(1, 1);
        System.out.print(ans);
    }
}

试题 H: 回忆迷宫

  • 这题我跳了

试题 I: 红绿灯

  • 写了30%的暴力做法,只有一段能冲刺,枚举是哪一段
import java.util.Scanner;

public class I {
    static int n, m ,k, v;
    static int a[] = new int[1010];
    static int b[] = new int[1010];
    static int c[] = new int[1010];
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        m = sc.nextInt();
        k = sc.nextInt();
        v = sc.nextInt();
        for (int i = 0; i < m; i++) {
            a[i] = sc.nextInt();
            b[i] = sc.nextInt();
            c[i] = sc.nextInt();
        }
        a[m] = n;
        int ans = Integer.MAX_VALUE;
        int zq;
        for (int i = 0; i <= m; i++) {
            int now = 0;
            int last = 0;
            //表示到达i前是否冲刺
            for (int j = 0; j <= m; j++) {
                if(i != j)
                {//不冲刺
                    now += a[j] - last;
                    //走这一段
                }
                if(j == m)
                {
                    break;
                }
                last = a[j];
                zq = b[j] + c[j];
                int s = now % zq;
                if(s >= b[j])
                {//红灯时间
                    now += zq - s;
                }
            }
//            System.out.println(now);
            ans = Math.min(now, ans);
        }
        System.out.print(ans);
    }
}
/*
90 2 2 2
30 20 20
60 20 20

350 2 100 1
50 50 10
250 60 200

260

350 2 100 1
50 50 10
250 60 20
*/

试题 J: 拉箱子

考试剩下最后 5 5 5分钟了,原本想写一个搜索的,我索性直接交上去一个随机数了

import java.util.Scanner;

public class Main {
    static int n, m, k, v;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        m = sc.nextInt();
        int a[][] = new int[n][m];
        for (int i = 0; i < n; i++) {
            a[i] = new int[m];
            for (int j = 0; j < m; j++) {
                a[i][j] = sc.nextInt();
            }
        }
        double ans = Math.random() * (n * m - 1);
        ans += 1;
        int l = (int) ans;
        System.out.println(l);
    }
}

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值