本文已参与「新人创作礼」活动,一起开启掘金创作之路。
蓝桥杯练习029
分巧克力
题目描述
儿童节那天有 K 位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友们。
小明一共有 N 块巧克力,其中第 i块是 Hi×Wi 的方格组成的长方形。为了公平起见,小明需要从这 N块巧克力中切出 K 块巧克力分给小朋友们。切出的巧克力需要满足:
- 形状是正方形,边长是整数;
- 大小相同;
例如一块 6x5 的巧克力可以切出 6 块 2x2 的巧克力或者 2 块 3x3 的巧克力。
当然小朋友们都希望得到的巧克力尽可能大,你能帮小明计算出最大的边长是多少么?
输入描述
第一行包含两个整数 N,K (1≤N,K≤10^5)。
以下 N 行每行包含两个整数 Hi,Wi (1≤Hi,Wi≤10^5)。
输入保证每位小朋友至少能获得一块 1x1 的巧克力。
输出描述
输出切出的正方形巧克力最大可能的边长。
输入输出样例
示例
输入
2 10
6 5
5 6
输出
2
运行限制
- 最大运行时间:2s
- 最大运行内存: 256M
解题思路
对于这道题的 d,可以按猜数的方法,猜 d 的取值。即对边长 d 的取值范围二分,这样复杂度一下子从 O(D) 优化到了O(logD)。具体操作是:
- 第一次:开始时 d的范围是 1∼D,试试中间值 D/2,如果这个值大了,就把范围缩小为 0∼D/2,如果这个值小了,就把范围缩小为 D/2∼D;
- 第二次,取新的中间值 D/4,再试…
- 第三次,…
- 直到找到合适的值为止。
代码
#include<iostream>
using namespace std;
int n,k;
int h[100005],w[100005];
//检查切出的巧克力是否满足条件
bool check(int d){
int num=0;//切出的巧克力数量
for(int i=0;i<n;i++){
num+=(h[i]/d)*(w[i]/d);
}
if(num>=k)return true;//满足条件返回true
else return false;//不满足返回false
}
int main()
{
cin>>n>>k;
for(int i=0;i<n;i++)
cin>>h[i]>>w[i];
int left=1;//左指针
int right=100005;//右指针
while(left<right){
int mid=(left+right)>>1;//中间值
if(check(mid))//当前长度可以分,考虑更长的
left=mid+1;
else//不可分,考虑更短的
right=mid;
}
cout<<left-1<<endl;
return 0;
}