题目背景
要保护环境。
题目描述
木材厂有 n 根原木,现在想把这些木头切割成 k 段长度均为 l 的小段木头(木头有可能有剩余)。
当然,我们希望得到的小段木头越长越好,请求出 l 的最大值。
木头长度的单位是 cm,原木的长度都是正整数,我们要求切割得到的小段木头的长度也是正整数。
例如有两根原木长度分别为 11 和 21,要求切割成等长的 6 段,很明显能切割出来的小段木头长度最长为 5。
输入格式
第一行是两个正整数 n,k,分别表示原木的数量,需要得到的小段的数量。
接下来 n 行,每行一个正整数 Li,表示一根原木的长度。
输出格式
仅一行,即 l 的最大值。
如果连 1cm 长的小段都切不出来,输出0。
输入输出样例
输入 #1复制
3 7 232 124 456
输出 #1复制
114
说明/提示
数据规模与约定
对于 100% 的数据,有 1≤n≤105,1≤k≤108,1≤Li≤108(i∈[1,n])。
思路:
这是一道经典的可以用二分解决的题。我们可以考虑从1到1e8(也就是1*10^8,题目给的木头最长长度)的范围找答案,那这么大的数据很明显需要一种思路来优化一下一般的n^2的暴力查找,那么就可以想到二分,我们可以用l和r做边界,l=1,r=1e8,用 (r+l)/2=mid 做二分答案的中间值,用while(l<=r)的循环通过不断调整mid的值,用mid值作为可以切割的长度,在while循环中开个1到n的for循环,让每个完整的木头与mid整除,得到符合长度要求的木头,用cnt累加。如果cnt(当前mid值下可以切割得到满足要求的木头数或者大于,那么我们就让l=mid+1来让长度尽可能的大,反之),找到满足条件的最大切割长度 。
主播的代码:
#include <iostream> #include<queue> #include<algorithm> #include<map> #include<vector> #include<set> #include<stack> #include<string> #include<math.h> #include <iomanip> #include<unordered_map> #include <unordered_set> #include<array> #define gets(S) fgets(S,sizeof(S),stdin) #define ll long long const ll N = 1e6 + 5; const ll Max = 0x3f3f3f3f; using namespace std; ll n, m; vector<ll>saki; ll ef(ll l, ll r) { ll mid = 0, cnt = 0, ans = 0; while (l <= r) { mid = (r + l) / 2; for (int i = 1; i <= n; i++) { cnt += saki[i] / mid; } if (cnt < m) { r = mid - 1; } else { l = mid + 1; } cnt = 0; } return r; } int main() { cin >> n >> m; saki.resize(n + 1); for (int i = 1; i <= n; i++) { cin >> saki[i]; } ll l = 1, r = 1e8; cout << ef(l, r) << endl; return 0; }