2023年第JavaB组 真题

A、阶乘求和


【问题描述】
令 S= 1!+ 2!+ 3!+ ..+ 202320232023!,求 S 的末尾 9 位数字。

public class Main {
    public static void main(String[] args) {
        //计算阶乘的算法
        long start = 1; 
        String s = "202320232023"; 
        long end = Long.parseLong(s); // 将字符串转换为长整型数字
        long sum = 0; 
        long cj = 1; 

        while (start <= end) {
            cj *= start; // 计算当前数字的阶乘
            cj %= 1000000000; // 取模 10^9,保留末尾 9 位数字
            sum += cj; // 将当前阶乘加到总和中
            sum %= 1000000000; // 取模 10^9,保留末尾 9 位数字
            start++; // 移动到下一个数字
            if (start > 40) // 如果当前数字大于 40,打印当前总和(调试用)
                System.out.println(sum);
        }

        // 输出最终的末尾 9 位数字
        System.out.println(sum);
    }
}

B、幸运数字


【问题描述】
哈沙德数是指在某个固定的进位制当中,可以被各位数字之和整除的正整 数。例如 126 是十进制下的一个哈沙德数,因为(126)10 mod(1+2+6)=0;126 也是八进制下的哈沙德数,因为(126)10=(176)8,(126) 10 mod(1+7+ 6)=0;同时 126 也是16 进制下的哈沙德数,因为(126)10=(7 e)16,(126) 10 mod(7 +é)=0。小蓝认为,如果一个整数在二进制、八进制、十进制、十六进制下均为哈沙德数,那么这个数字就是幸运数字,第1至第10个幸运数字的十进制表示为:1,2,4,6,8,40,48,72,120,126...。现在他想知道第 2023个幸运数字是多少?你只需要告诉小蓝这个整数的十进制表示即可。

public class Main {
    public static void main(String[] args) {
        // 十进制转成其他进制
                Integer.toBinaryString(int i)
                Integer.toOctalString(int i)
                Integer.toHexString(int i)
        // 二进制转成十进制:
                String binary = "1010";
                int decimalFromBinary = Integer.parseInt(binary, 2);

        int j = 0; 
        for (int i = 1; i < 10000000; i++) {
            if (BaseConversion(i)) {
                j++; 
                if (j == 2023) {
                    System.out.println(i); 
                    break;
                }
            }
        }
    }

    /**
     * 检查一个数字是否满足条件:
     * 该数字在十进制、二进制、八进制和十六进制下,都能被其各位数字之和整除。
     */
    public static boolean BaseConversion(int n) {
        // 十进制
        int sum = 0; // 用于存储各位数字之和
        int x = n; // 临时变量,用于计算
        // 计算十进制下的各位数字之和
        while (x != 0) {
            sum += (x % 10); // 取出当前最低位的数字并加到 sum 中
            x /= 10; // 去掉当前最低位
        }
        if (n % sum != 0) {
            return false;
        }

        // 二进制
        sum = 0; // 重置 sum
        x = n; // 重置 x
        // 计算二进制下的各位数字之和
        while (x != 0) {
            sum += (x % 2); // 取出当前最低位的数字并加到 sum 中
            x /= 2; // 去掉当前最低位
        }
        if (n % sum != 0) {
            return false;
        }

        // 八进制
        sum = 0; // 重置 sum
        x = n; // 重置 x
        // 计算八进制下的各位数字之和
        while (x != 0) {
            sum += (x % 8); // 取出当前最低位的数字并加到 sum 中
            x /= 8; // 去掉当前最低位
        }
        if (n % sum != 0) {
            return false;
        }

        // 十六进制
        int[] arr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; // 十六进制数字映射
        sum = 0; // 重置 sum
        x = n; // 重置 x
        // 计算十六进制下的各位数字之和
        while (x != 0) {
            sum += (arr[x % 16]); // 取出当前最低位的数字并加到 sum 中
            x /= 16; // 去掉当前最低位
        }
        if (n % sum != 0) {
            return false;
        }

        // 如果所有进制下都能被各位数字之和整除,返回 true
        return true;
    }
}

C:数组分割

        

【问题描述】
小蓝有一个长度为 N 的数组 A = [ A 0 , A 1 , . . . , A N − 1 ] 。现在小蓝想要从 A 对应的数组下标所构成的集合 I = { 0 , 1 , 2 , . . . , N − 1 } 中找出一个子集 R 1 ,那么 R 1在 I 中的补集为 R 2 。记 S 1 = ∑ r ∈ R 1 A r , S 2 = ∑ r ∈ R 2 A r,我们要求 S 1 和 S 2 均为 偶数,请问在这种情况下共有多少种不同的 R 1。当 R1 或 R 2 为空集时我们将 S 1 或 S 2 视为 0。

【输入格式】
第一行一个整数 T ,表示有 T 组数据。 接下来输入 T 组数据,每组数据包含两行:第一行一个整数 N ,表示数组 A 的长度;第二行输入 N 个整数从左至右依次为 A 0 , A 1 , . . . , A N − 1 ,相邻元素之 间用空格分隔。
【输出格式】
对于每组数据,输出一行,包含一个整数表示答案

D、矩形总面积

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int x1 = sc.nextInt(); // 第一个矩形左下角的 x 坐标
        int y1 = sc.nextInt(); // 第一个矩形左下角的 y 坐标
        int x2 = sc.nextInt(); // 第一个矩形右上角的 x 坐标
        int y2 = sc.nextInt(); // 第一个矩形右上角的 y 坐标
        int x3 = sc.nextInt(); // 第二个矩形左下角的 x 坐标
        int y3 = sc.nextInt(); // 第二个矩形左下角的 y 坐标
        int x4 = sc.nextInt(); // 第二个矩形右上角的 x 坐标
        int y4 = sc.nextInt(); // 第二个矩形右上角的 y 坐标

        // 计算第一个矩形的面积
        long area1 = (long) (x2 - x1) * (y2 - y1);
        // 计算第二个矩形的面积
        long area2 = (long) (x4 - x3) * (y4 - y3);

        // 计算重叠部分的宽度和高度
        long l = Math.min(x2, x4) - Math.max(x1, x3);
        long w = Math.min(y2, y4) - Math.max(y1, y3);

        // 如果有重叠部分
        long overlapArea = 0;
        if (l >= 0 && w >= 0) {
            overlapArea = l * w;
        }

        // 计算总面积
        long totalArea = area1 + area2 - overlapArea;

        // 输出总面积
        System.out.println(totalArea);
    }
}

E、蜗牛(时间限制: 1.0s 内存限制: 512.0MB)


【问题描述】
这天,一只蜗牛来到了二维坐标系的原点。 在 x 轴上长有 n 根竹竿。它们平行于 y 轴,底部纵坐标为 0 ,横坐标分别 为 x 1 , x 2 , ..., x n 。竹竿的高度均为无限高,宽度可忽略。蜗牛想要从原点走到第 n 个竹竿的底部也就是坐标 ( x n , 0) 。它只能在 x 轴上或者竹竿上爬行,在 x 轴
上爬行速度为 1 单位每秒;由于受到引力影响,蜗牛在竹竿上向上和向下爬行 的速度分别为 0 . 7 单位每秒和 1 . 3 单位每秒。 为了快速到达目的地,它施展了魔法,在第 i 和 i + 1 根竹竿之间建立了传 送门(0 < i < n ),如果蜗牛位于第 i 根竹竿的高度为 a i 的位置 ( x i , a i ) ,就可以 瞬间到达第 i + 1 根竹竿的高度为 b i +1 的位置 ( x i +1 , b i +1 ), 请计算蜗牛最少需要多少秒才能到达目的地。
【输入格式】
输入共 1 + n 行,第一行为一个正整数 n ;
第二行为 n 个正整数 x 1 , x 2 , . . . , x n ;
后面 n − 1 行,每行两个正整数 a i , b i +1 。
【输出格式】
输出共一行,一个浮点数表示答案( 四舍五入保留两位小数 )。

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt(); // 竹竿数量
        int[] x = new int[n]; // 竹竿横坐标
        for (int i = 0; i < n; i++) {
            x[i] = sc.nextInt();
        }

        // 动态规划数组,dp[i] 表示到达第 i 根竹竿底部的最小时间
        double[] dp = new double[n];
        dp[0] = x[0]; // 从原点到第一根竹竿的时间

        // 读取每对竹竿之间的高度信息
        int[] a = new int[n - 1];
        int[] b = new int[n - 1];
        for (int i = 0; i < n - 1; i++) {
            a[i] = sc.nextInt();
            b[i] = sc.nextInt();
        }

        // 动态规划计算最短时间
        for (int i = 1; i < n; i++) {
            // 不使用传送门的时间
            dp[i] = dp[i - 1] + (x[i] - x[i - 1]);

            // 使用传送门的时间
            double timeWithTeleport = dp[i - 1] + a[i - 1] / 0.7 + (x[i] - x[i - 1]) + b[i] / 1.3;
            dp[i] = Math.min(dp[i], timeWithTeleport);
        }

        // 输出总时间,四舍五入保留两位小数
        System.out.printf("%.2f\n", dp[n - 1]);
    }
}

F、合并区域

【问题描述】
小蓝在玩一款种地游戏。现在他被分配给了两块大小均为 N × N 的正方形 区域。这两块区域都按照 N × N 的规格进行了均等划分,划分成了若干块面积 相同的小区域,其中每块小区域要么是岩石,要么就是土壤,在垂直或者水平 方向上相邻的土壤可以组成一块土地。现在小蓝想要对这两块区域沿着边缘进 行合并,他想知道合并以后可以得到的最大的一块土地的面积是多少(土地的 面积就是土地中土壤小区域的块数)? 在进行合并时,小区域之间必须对齐。可以在两块方形区域的任何一条边 上进行合并,可以对两块方形区域进行 90 度、 180 度、 270 度、 360 度的旋转, 但不可以进行上下或左右翻转,并且两块方形区域不可以发生重叠。
【输入格式】
第一行一个整数 N 表示区域大小。 接下来 N 行表示第一块区域,每行 N 个值为 0 或 1 的整数,相邻的整数 之间用空格进行分隔。值为 0 表示这块小区域是岩石,值为 1 表示这块小区域 是土壤。 再接下来 N 行表示第二块区域,每行 N 个值为 0 或 1 的整数,相邻的整 数之间用空格进行分隔。值为 0 表示这块小区域是岩石,值为 1 表示这块小区 域是土壤。
【输出格式】
一个整数表示将两块区域合并之后可以产生的最大的土地面积。

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt(); // 读取区域大小

        int[][] region1 = new int[N][N];
        int[][] region2 = new int[N][N];

        // 读取第一块区域
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                region1[i][j] = sc.nextInt();
            }
        }

        // 读取第二块区域
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                region2[i][j] = sc.nextInt();
            }
        }

        // 计算每块区域的土地面积
        int maxArea1 = calculateMaxLandArea(region1);
        int maxArea2 = calculateMaxLandArea(region2);

        // 合并区域并计算最大土地面积
        int maxCombinedArea = 0;
        for (int rotation = 0; rotation < 4; rotation++) {
            int[][] rotatedRegion2 = rotateRegion(region2, rotation);
            int combinedArea = calculateCombinedLandArea(region1, rotatedRegion2);
            maxCombinedArea = Math.max(maxCombinedArea, combinedArea);
        }

        // 输出最大土地面积
        System.out.println(maxCombinedArea);
    }

    /**
     * 计算区域的最大土地面积
     */
    private static int calculateMaxLandArea(int[][] region) {
        int maxArea = 0;
        boolean[][] visited = new boolean[region.length][region[0].length];
        for (int i = 0; i < region.length; i++) {
            for (int j = 0; j < region[0].length; j++) {
                if (region[i][j] == 1 && !visited[i][j]) {
                    int area = dfs(region, visited, i, j);
                    maxArea = Math.max(maxArea, area);
                }
            }
        }
        return maxArea;
    }

    /**
     * 深度优先搜索计算土地面积
     */
    private static int dfs(int[][] region, boolean[][] visited, int i, int j) {
        if (i < 0 || i >= region.length || j < 0 || j >= region[0].length || region[i][j] == 0 || visited[i][j]) {
            return 0;
        }
        visited[i][j] = true;
        int area = 1;
        area += dfs(region, visited, i - 1, j);
        area += dfs(region, visited, i + 1, j);
        area += dfs(region, visited, i, j - 1);
        area += dfs(region, visited, i, j + 1);
        return area;
    }

    /**
     * 旋转区域
     */
    private static int[][] rotateRegion(int[][] region, int rotation) {
        int N = region.length;
        int[][] rotatedRegion = new int[N][N];
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                switch (rotation) {
                    case 0:
                        rotatedRegion[i][j] = region[i][j];
                        break;
                    case 1:
                        rotatedRegion[i][j] = region[N - 1 - j][i];
                        break;
                    case 2:
                        rotatedRegion[i][j] = region[N - 1 - i][N - 1 - j];
                        break;
                    case 3:
                        rotatedRegion[i][j] = region[j][N - 1 - i];
                        break;
                }
            }
        }
        return rotatedRegion;
    }

    /**
     * 计算合并后的最大土地面积
     */
    private static int calculateCombinedLandArea(int[][] region1, int[][] region2) {
        int N = region1.length;
        int maxArea = 0;
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                if (region1[i][j] == 1 && region2[i][j] == 1) {
                    int area = dfsCombined(region1, region2, i, j);
                    maxArea = Math.max(maxArea, area);
                }
            }
        }
        return maxArea;
    }

    /**
     * 深度优先搜索计算合并后的土地面积
     */
    private static int dfsCombined(int[][] region1, int[][] region2, int i, int j) {
        if (i < 0 || i >= region1.length || j < 0 || j >= region1[0].length || region1[i][j] == 0 || region2[i][j] == 0) {
            return 0;
        }
        region1[i][j] = 0;
        region2[i][j] = 0;
        int area = 1;
        area += dfsCombined(region1, region2, i - 1, j);
        area += dfsCombined(region1, region2, i + 1, j);
        area += dfsCombined(region1, region2, i, j - 1);
        area += dfsCombined(region1, region2, i, j + 1);
        return area;
    }
}

G、买二赠一

【问题描述】
某商场有 N 件商品,其中第 i 件的价格是 A i 。现在该商场正在进行 “ 买二 赠一” 的优惠活动,具体规则是: 每购买 2 件商品,假设其中较便宜的价格是 P (如果两件商品价格一样,
则 P 等于其中一件商品的价格),就可以从剩余商品中任选一件价格不超过 P /2 的商品,免费获得这一件商品。可以通过反复购买 2 件商品来获得多件免费商 品,但是每件商品只能被购买或免费获得一次。 小明想知道如果要拿下所有商品(包含购买和免费获得),至少要花费多少钱?
【输入格式】
第一行包含一个整数 N 。
第二行包含 N 个整数,代表 A 1 , A 2 , A 3 , . . . , A N
【输出格式】
输出一个整数,代表答案。

        一种骗分写法:

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

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt(); // 商品数量
        int[] prices = new int[N]; // 商品价格
        for (int i = 0; i < N; i++) {
            prices[i] = sc.nextInt();
        }
        sc.close();

        // 对商品价格进行排序
        Arrays.sort(prices);

        long totalCost = 0; // 总成本
        int i = N - 1; // 从最贵的商品开始

        // 模拟购买和免费获得的过程
        while (i >= 0) {
            if (i >= 2) {
                // 购买两件商品
                totalCost += prices[i] + prices[i - 1];
                // 免费获得一件商品
                i -= 3;
            } else if (i == 1) {
                // 购买两件商品
                totalCost += prices[1] + prices[0];
                i -= 2;
            } else if (i == 0) {
                // 只有一件商品,直接购买
                totalCost += prices[0];
                i -= 1;
            }
        }

        // 输出总成本
        System.out.println(totalCost);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值