一、题目
儿童节那天有 K 位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友们。
小明一共有 N 块巧克力,其中第 i 块是 Hi * Wi 的方格组成的长方形。为了公平起见,
小明需要从这 N 块巧克力中切出 K 块巧克力分给小朋友们。切出的巧克力需要满足:
1.形状是正方形,边长是整数;
2.大小相同;
例如一块 6x5 的巧克力可以切出 6 块 2x2 的巧克力或者 2 块 3x3 的巧克力。
当然小朋友们都希望得到的巧克力尽可能大,你能帮小明计算出最大的边长是多少么?
输入描述
第一行包含两个整数 N,K (1<=N,k<=105)。
以下 N 行每行包含两个整数 Hi , Wi (1<=Hi , Wi <=105)
输入保证每位小朋友至少能获得一块 1x1 的巧克力。
输出描述
输出切出的正方形巧克力最大可能的边长。
输入输出样例
示例1:
输入:
2 10
6 5
5 6
输出:
2
二、解题思路
首先,由题可得最后分的巧克力需要满足以下两个条件:
- 巧克力的数量需要大于等于人数
- 巧克力的边长要尽可能的最大
我们先假设已经找到了最大的那条边长,那么那么巧克力可以分成的最大块数则是(巧克力的长//最大边长)* (巧克力的宽//最大边长)
只要循环,将每块巧克力分得的块数相加总和大于人数即可。
那么剩下的就是如何去找到这个最大边长了。
首先,边长的范围是1到100000,如果使用顺序查找的话,当巧克力的最大边长为99999呢?岂不是得循环99999次,这是效率较低的做法。这里我们可以用二分法找到找中间值。定义两个指针变量,head,tail,中间值mid = (head+tail)//2,将中间值作为最大边长判断是否满足条件。如果中间值算得的巧克力块数小于实际所需块数,则说明最大边长太大了,此时将tail指针移动到mid前一位,并重新计算mid的值,如果中间值算得的巧克力块数大于实际所需块数,则需判断最大边长是否还有可增加的空间,此时将head移动到mid前一位。如此往复,直到找到符合条件的最大边长。
代码
n, k = map(int, input().split())
longLi = []
widthLi = []
for _ in range(n):
l, width = map(int, input().split())
longLi.append(l)
widthLi.append(width)
def check(w):
res = 0
for l, width in zip(longLi, widthLi):
res += (l // w) * (width // w)
if res >= k:
return True
return False
head, tail = 1, 100000
while head <= tail:
mid = (head + tail) // 2
if (not check(mid)):
tail = mid - 1
else:
head = mid + 1
print(tail)
此次碰到的小问题:用split()和split(" “)会有一点区别:
split()第一个传入的是分隔符,默认为所有的空字符,包括空格、换行(\n)、制表符(\t)等。
当使用split(” ")时会少考虑到换行符,导致提交时测试用例无法全部通过