2023年第十四届蓝桥杯Java B组D、G题解

试题D:矩形总面积

【问题描述】
平面上有个两个矩形 R 1 和 R 2 ,它们各边都与坐标轴平行。设 ( x 1 , y 1 ) 和
( x 2 , y 2 ) 依次是 R 1 的左下角和右上角坐标, ( x 3 , y 3 ) 和 ( x 4 , y 4 ) 依次是 R 2 的左下
角和右上角坐标,请你计算 R 1 和 R 2 的总面积是多少?
注意:如果 R 1 和 R 2 有重叠区域,重叠区域的面积只计算一次。
【输入格式】
输入只有一行,包含 8 个整数,依次是: x 1 , y 1 , x 2 , y 2 , x 3 , y 3 , x 4 和 y 4 。
【输出格式】
一个整数,代表答案。
【样例输入】
2 1 7 4 5 3 8 6
【样例输出】
22

【评测用例规模与约定】
对于 20 % 的数据, R 1 和 R 2 没有重叠区域。
对于 20 % 的数据,其中一个矩形完全在另一个矩形内部。
对于 50 % 的数据,所有坐标的取值范围是 [0 , 10 ^3 ] 。
对于 100 % 的数据,所有坐标的取值范围是 [0 , 10^ 5 ] 。

【样例说明】
样例中的两个矩形如图所示:

分析:

本题难点在于两个矩形部分重合的情况,我在比赛时是分三种情况讨论的(无重合,完全重合,部分重合)。

先将两个矩形需要占的最大板块的左下角与右上角找出来,然后依次遍历这个板块被占领的地区。

import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int x1 = scanner.nextInt(), y1 = scanner.nextInt();
        int x2 = scanner.nextInt(), y2 = scanner.nextInt();
        int x3 = scanner.nextInt(), y3 = scanner.nextInt();
        int x4 = scanner.nextInt(), y4 = scanner.nextInt();
        // 计算面积并且减去重叠部分的面积
        long area = (long)(x2 - x1) * (y2 - y1) + (long)(x4 - x3) * (y4 - y3);
        int overlapWidth = Math.max(0, Math.min(x2, x4) - Math.max(x1, x3)); // 重叠部分宽度
        int overlapHeight = Math.max(0, Math.min(y2, y4) - Math.max(y1, y3)); // 重叠部分高度
        if (overlapWidth > 0 && overlapHeight > 0) { // 存在重叠部分
            area -= (long)overlapWidth * overlapHeight;
        }
        System.out.println(area);
    }
}

 

试题G:买二赠一

题目描述

某商场有 N 件商品,其中第 i 件的价格是 Ai。现在该商场正在进行 “买二赠一” 的优惠活动,具体规则是:

每购买 2 件商品,假设其中较便宜的价格是 P(如果两件商品价格一样,则 P 等于其中一件商品的价格),就可以从剩余商品中任选一件价格不超过 P/2的商品,免费获得这一件商品。可以通过反复购买 2 件商品来获得多件免费商品,但是每件商品只能被购买或免费获得一次。

小明想知道如果要拿下所有商品(包含购买和免费获得),至少要花费多少钱?

输入格式

第一行包含一个整数 N。

第二行包含 N 个整数,代表 A1, A2, A3, . . . ,AN。

输出格式

输出一个整数,代表答案。

样例输入

7
1 4 2 8 5 7 1

样例输出

25

提示

小明可以先购买价格 4 和 8 的商品,免费获得一件价格为 1 的商品;再后买价格为 5 和 7 的商品,免费获得价格为 2 的商品;最后单独购买剩下的一件价格为 1 的商品。总计花费 4 + 8 + 5 + 7 + 1 = 25。不存在花费更低的方案。

对于 30% 的数据,1 ≤ N ≤ 20。

对于 100% 的数据,1 ≤ N ≤ 5 × 105,1 ≤ Ai ≤ 109

解题思路:

贪心+排序

首先排序,每次循环将两个最大的商品可以免费的价格用队列存放,然后判断数量低于免费的就可以直接免费掉。

import java.util.*;
   
public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        int[] a = new int[n + 1];
        for(int i = 1; i <= n; i++){
            a[i] = scan.nextInt();
        }
        Arrays.sort(a); // 升序排序
        Queue queue = new LinkedList<>(); // 存放免费机会
        long res = 0;
        while (n > 0){
            while (!queue.isEmpty() && n > 0){   
                if(queue.peek() >= a[n]){ // 取出最大免费机会比较可以免费则指针向后并删除当前免费机会
                    queue.poll();
                    n--;
                }else {
                    break;  // 否则退出
                }
            }
            if(n > 0) {
                res += a[n]; 
                n--;
            }
            while (!queue.isEmpty() && n > 0){   
                if(queue.peek() >= a[n]){ // 取出最大免费机会比较可以免费则指针向后并删除当前免费机会
                    queue.poll();
                    n--;
                }else {
                    break;  // 否则退出
                }
            }
            if(n > 0) { // 防止越界,并取买的两个数中最小的价值的一半添加到免费机会
                res += a[n];
                queue.offer(a[n] / 2.0);
                n--;
            }
        }
        System.out.println(res);
    }
}

最后希望正在看这篇文章的uu们蓝桥杯(或其他算法竞赛)都能取得好成绩!

如有错误或改进方案,欢迎评论区讨论指正。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值