题目描述
儿童节那天有 K K K 位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友们。
小明一共有 N N N 块巧克力,其中第 i i i 块是 H i × W i H_i \times W_i Hi×Wi 的方格组成的长方形。
为了公平起见,小明需要从这 N N N 块巧克力中切出 K K K 块巧克力分给小朋友们。切出的巧克力需要满足:
-
形状是正方形,边长是整数。
-
大小相同。
例如一块 6 × 5 6 \times 5 6×5 的巧克力可以切出 6 6 6 块 2 × 2 2 \times 2 2×2 的巧克力或者 2 2 2 块 3 × 3 3 \times 3 3×3 的巧克力。
当然小朋友们都希望得到的巧克力尽可能大,你能帮小 H i H_i Hi 计算出最大的边长是多少么?
输入格式
第一行包含两个整数 N N N 和 K K K。 ( 1 ≤ N , K ≤ 1 0 5 ) (1 \le N,K \le 10^5) (1≤N,K≤105)。
以下 N N N 行每行包含两个整数 H i H_i Hi 和 W i W_i Wi。 ( 1 ≤ H i , W i ≤ 1 0 5 ) (1 \le H_i,W_i \le 10^5) (1≤Hi,Wi≤105)。
输入保证每位小朋友至少能获得一块 1 × 1 1 \times 1 1×1 的巧克力。
输出格式
输出切出的正方形巧克力最大可能的边长。
样例 #1
样例输入 #1
2 10
6 5
5 6
样例输出 #1
2
提示
蓝桥杯 2022 省赛 A 组 I 题。
题解
这一题的目标是求一个边长,正方形的边长,满足需求。
需求是:每个小朋友都拿到尽可能大的正方形巧克力
首先看到这个题
(
1
≤
H
i
,
W
i
≤
1
0
5
)
(1 \le H_i,W_i \le 10^5)
(1≤Hi,Wi≤105)
别管这个H和W怎么样,其实是可以视为一个东西,而我们目标是一个边长e,也就是说,上限下限已知,区间升序,
在有序的数据集合中快速查找目标元素
二分查找很适合这种情形
先看一下二分伪代码,再看看怎么把二分套到这道题上:
l 下限
r 上限
while l + 1 < r:
mid = l + r >> 1
if 满足需求(mid):
视情况定 是 r = mid 还是 l = mid
else:
与上面反过来
输出 l or r
我们这题
l = 0, r = 100001
最后输出 e
那么如果mid满足需求, 那么 可以理解为 mid 小了, 我们要往 大了试试
如果不满足需求, 那么可以理解为 mid 大了, 我们要往小了分
那么就可以得出代码:
l, r = 0, 1e5+1
while l + 1 < r:
mid = (l + r) // 2
if is_ok(mid):
l = mid
else:
r = mid
为什么l不是1,r不是1e5
因为l是1,r是1e5时,这两个数取不到,遇到数据:
1 1
1e5 1e5
报错
1 1
1 1
报错
需求怎么计算:
需求是计算块数,这个不太难,就是遍历一遍每块巧克力,看看每块巧克力能分出多少个边长为e的正方形巧克力,一个大巧克力可以分出的小巧克力个数的公式如下:
(H // e) * ( W // e)
最终答案:
def is_ok(edge):
ans = 0
global N, H, W, K
for i in range(N):
ans += (H[i] // edge) * (W[i] // edge)
return ans >= K
N, K = map(int, input().strip().split())
H, W = [], []
for i in range(N):
h, w = map(int, input().strip().split())
H.append(h)
W.append(w)
l, r = 0, 1e5+1
while l + 1 < r:
mid = (l + r) // 2
if is_ok(mid):
l = mid
else:
r = mid
print(int(l))