P4058 [Code+#1] 木材 二分答案
解题思路
这道题目要求我们找到最少需要等待多少个月,才能收集到足够长度和数量的木材。主要思路是使用二分查找来确定最小满足条件的月份。
关键点分析:
-
二分查找的应用:我们需要找到最小的月份mid,使得在这个月份之后,所有满足高度条件的树的总和≥S。二分查找可以高效地缩小搜索范围。
-
检查函数check(mid):对于给定的月份mid,计算每棵树的高度(初始高度 + 每月生长高度 × 月份数),并累加满足高度≥L的树的高度,判断总和是否≥S。
-
边界处理:特别处理0个月的情况,即初始状态是否已经满足条件。
时间复杂度分析:
-
二分查找的时间复杂度是O(log(max_months)),其中max_months是可能的最大月份,这里是1e18。
-
每次check(mid)的时间复杂度是O(n),因为需要遍历所有树。
-
总的时间复杂度是O(n log(max_months)),对于n=2e5来说是可行的。
代码注释
#include<bits/stdc++.h> #define ll unsigned long long // 使用unsigned long long防止乘法溢出 using namespace std; const int N = 2e5 + 10; ll n, s, l; // n:树的数量,s:订单总量,l:单块木料的最小长度 ll a[N], h[N]; // a[i]:第i棵树每月生长高度,h[i]:第i棵树的初始高度 // 检查函数:判断在mid个月后是否能满足订单需求 bool check(ll mid) { ll sum = 0; // 累计满足条件的树木总高度 for(int i = 1; i <= n; i++) { // 如果当前树在mid个月后的高度≥L,则计入总和 if(h[i] + mid * a[i] >= l){ sum += h[i] + mid * a[i]; } // 如果已经满足订单需求,提前退出循环 if(sum >= s) break; } // 返回是否满足订单需求 return sum >= s; } int main() { // 输入数据 cin >> n >> s >> l; for(int i = 1; i <= n; i++) scanf("%lld",&h[i]); for(int i = 1; i <= n; i++) scanf("%lld",&a[i]); ll L = 0, R = 1e18, ans; // 初始化二分查找的左右边界 // 特判0个月是否满足条件 if(check(0)){ cout << 0; return 0; } // 二分查找 while(L <= R) { ll mid = (L + R) / 2; if(check(mid)) // 如果mid个月满足条件,尝试寻找更小的月份 { ans = mid; R = mid - 1; } else // 否则增加月份 { L = mid + 1; } } cout << ans; // 输出最小满足条件的月份 return 0; }

浙公网安备 33010602011771号