day07 1227分巧克力(整数二分)

1227. 分巧克力

儿童节那天有 K K K 位小朋友到小明家做客。

小明拿出了珍藏的巧克力招待小朋友们。

小明一共有 N N N 块巧克力,其中第 i i i 块是 H i × W i H_i×W_i Hi×Wi 的方格组成的长方形。

为了公平起见,小明需要从这 N N N 块巧克力中切出 K K K 块巧克力分给小朋友们。

切出的巧克力需要满足:

  1. 形状是正方形,边长是整数
  2. 大小相同

例如一块 6 × 5 6×5 6×5 的巧克力可以切出 6 6 6 2 × 2 2×2 2×2 的巧克力或者 2 2 2 3 × 3 3×3 3×3 的巧克力。

当然小朋友们都希望得到的巧克力尽可能大,你能帮小明计算出最大的边长是多少么?

输入格式
第一行包含两个整数 N N N K K K

以下 N N N 行每行包含两个整数 H i H_i Hi W i W_i Wi

输入保证每位小朋友至少能获得一块 1 × 1 1×1 1×1 的巧克力。

输出格式
输出切出的正方形巧克力最大可能的边长。

数据范围
1 ≤ N , K ≤ 105 1≤N,K≤105 1N,K105,
1 ≤ H i , W i ≤ 105 ≤H_i,W_i≤105 Hi,Wi105
输入样例:

2 10
6 5
5 6

输出样例:

2

题意: 给定若干个矩形,从中切割出不少于 K K K个边长相同的正方形,问正方形个数不少于 K K K时,边长最大能达到多少

解题思路:

显然是一个二分答案的思路,题目中说了每个小朋友至少能分得一个1×1大小的正方形,所以边长最小为1,最大值可以设定一个足够大的数,比如题目中给的数据范围100000,若当前选择的边长满足要求,则说明还有可能取更长的边长,当然也有可能不能取更长了,答案就是当前这个;若当前这个边长不能满足要求,则说明当前边长不可能是最终答案
满足要求在此题中的意思是至少能够分得K个当前选择边长的正方形

我在此题所选择的性质是当切分的巧克力的边长为mid时,能够切出k个来,画图如下:

在这里插入图片描述

结论:要找的点是红色区间的右边界,即能满足切出的巧克力至少有k个时,切分的巧克力的边长的最大值
如何判断是否满足这个性质?

很容易就可以推出,若当前所取的边长为mid,对于一个矩形来说,只需要分别用它的长和宽整除这个mid,然后把结果相乘,就得到这个矩形能够分成多少个边长为mid的正方形了,把所有的矩形分割的结果相加,就得到总数,可以和K比较了。

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

public class Main {
     public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int k = scanner.nextInt();
        List<Segment> list = new ArrayList<>();//存储输入的所有巧克力的大小
        for(int i = 0;i < n;i++ ){
            list.add(new Segment(scanner.nextInt(),scanner.nextInt()));
        }
        int l = 1,r = 100000;//题目给出的巧克力的长宽范围,那么切分后的巧克力长宽也在该范围内
        while(l < r){//结束的时候l = r,故最后输出l和输出r都是可以的
            //由于是用的l = mid的模板,故这里要加1,即应向上取整,避免死循环
            //(如l = 3, r = 4,则mid=3,若更新为l=mid,则区间还是3,4,无限死循环了)
            int mid = l + r + 1>> 1;
            if(check(list,k,mid)){//判断当切分的巧克力边长为mid时,能否切出k块出来
                l = mid;//能切出k块,说明边长可以更长,故继续在[mid,r]中尝试切出更长的边长
            }else{
                r = mid - 1;//边长为mid时,无法切出k块,则在[l,mid-1]中找合适的边长,mid已知不行了,故是mid-1
            }
        }
        System.out.println(l);
    }

    private static boolean check(List<Segment> list, int k, int mid) {
        int cnt = 0;
        for(Segment seg : list){
            //当边长为mid时,一块大巧克力能切出的小巧克力块数为seg.length / mid * (seg.width / mid);
            //注意第二个括号不能省,因为存在取整,先乘后除与先除后乘得到的结果不一样 ,
            //如3*2/4 = 1与3*(2/4)=0不同
            cnt += (seg.length / mid) * (seg.width / mid);
        }
        return cnt >= k;
    }
}

class Segment{//代表每块巧克力的长与宽的类
    public int length;
    public int width;
    Segment(int length,int width){
        this.length = length;
        this.width = width;
    }
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值