题目来源
洛谷P2440
难度
题目描述
木材厂有 n 根原木,现在想把这些木头切割成 k 段长度均为 l 的小段木头(木头有可能有剩余)。
当然,我们希望得到的小段木头越长越好,请求出 l 的最大值。
木头长度的单位是 cm,原木的长度都是正整数,我们要求切割得到的小段木头的长度也是正整数。
例如有两根原木长度分别为 11 和 21,要求切割成等长的 6 段,很明显能切割出来的小段木头长度最长为 5。
输入格式
第一行是两个正整数 n,k,分别表示原木的数量,需要得到的小段的数量。
接下来 n 行,每行一个正整数 Li,表示一根原木的长度。
输出格式
仅一行,即 l 的最大值。
如果连 1cm 长的小段都切不出来,输出 0
。
样例 #1
样例输入 #1
3 7
232
124
456
样例输出 #1
114
提示
数据规模与约定
对于 100 的数据,有 1≤n≤105,1≤k≤108,1≤Li≤108(i∈[1,n])。
参考题解
前导知识
- 二分查找
算法分析
- 因为原木长度 Li≤108 ,我们只要通过二分查找在 [0,108] 区间内寻找满足条件的小段木头长度。
- 题目中,如果原木长度是有序的,那么只需要在 [0,Limin] 区间内寻找答案。
- 如果原木无序,则不需要给原木长度排序,直接在 [0,108] 区间内寻找。
参考代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
#include <iostream>
using namespace std;
int wood[100000];
//a数组中的n根原木,切割成li厘米长的小段,返回小段木头的数量
int cnt(int a[], int n, int li)
{
int ans = 0;
for (int i = 0; i < n; ++i)
{
ans += a[i] / li;
}
return ans;
}
int main()
{
int n, k;
//l为小段木头的最小长度,r为小段木头的最大长度
int l = 0, r = 100000000, mid;
cin >> n >> k;
for (int i = 0; i < n; ++i)
cin >> wood[i];
while (r - l > 1)
{
mid = l + (r - l) / 2;
//因为得到小段木头的最大长度,所以=k时,移动左边界,寻找满足条件更长的小段木头。
if (cnt(wood, n, mid) >= k)
l = mid;
else
r = mid;
}
cout << l << endl;
return 0;
}
|