前缀和 + 二分答案
因为通过的关卡数量与消耗的能量成正相关,所以使用二分答案来降低时间复杂度。
而本题求最大通过数时,不可以简单的用贪心直接比较两个数组中当前下标谁更小,否则会出现反例,比如a:1 888 888 888,b: 999 1 1 1,如果简单的贪心,那这个例子就会一直在a数组中选择关卡,但是实际上选b数组会更好。
所以无法通过当前关卡的大小来判断究竟是选择a数组还是b数组,就像之前最大数组和那道题目一样,但他们都有一个共同点,就是求的都是一段连续区间的和,所以使用前缀和对所有情况进行一一枚举,找到在当前给出的通过关卡数量的前提下,需要的最小能量。
如果这个最小能量小于等于题目给出的能量,那就增加假定的通过的关卡数量,直到找出最大的通过关卡数量。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int maxn = 2e5 + 9;
ll a[maxn];
ll b[maxn];
bool check(int x, int n, int m, ll k) {
ll num = 1e10;
int j = 0;
for (int i = 0; i <= n; i++) {
j = x - i;
if (j < 0) break;
if (j > m) continue;
else num = min(num, a[i] + b[j]);
}
if (num > k) return true;
else return false;
}
int main()
{
int n, m;
ll k; cin >> n >> m >> k;
for (int i = 1; i <= n; i++) {
cin >> a[i];
a[i] += a[i - 1];
}
for (int i = 1; i <= m; i++) {
cin >> b[i];
b[i] += b[i - 1];
}
int l = 0, r = m + n + 1;
while (l + 1 < r) {
int mid = (l + r) / 2;
if (check(mid, n, m, k)) r = mid;
else l = mid;
}
cout << l;
return 0;
}