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 块巧克力分给小朋友们。
切出的巧克力需要满足:
- 形状是正方形,边长是整数
- 大小相同
例如一块 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
1≤N,K≤105,
1
≤
H
i
,
W
i
≤
105
≤H_i,W_i≤105
≤Hi,Wi≤105
输入样例:
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;
}
}