由题意可知,饭局的隔阂值为隔阂最大的那一对朋友的隔阂,也就是所有参与饭局的朋友中财富最大的减去财富最小的。根据贪心的思想,如果邀请了其中两名成员和,那么想要让愉悦值最大,应当尽可能多的邀请财富值在两者之间的其他朋友。
将所有成员按照财富从小到大排序,就可以将题目转化为求连续区间的愉悦值之和大于等于k的情况下,首尾元素财富值之差的最小值。我们很容易想到用前缀和与双指针的思想来解题。
我们维护一个愉悦值的前缀和数组sum,那么连续区间[l, r]的愉悦值之和为sum[r] - sum[l-1]。
双指针的处理就很简单了,具体处理方法直接看代码吧。
统计下时间复杂度:排序O(nlogn),计算前缀和数组O(n),双指针遍历O(n)。
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
struct py {
int a, b;
};
int main() {
int n;
long long k;
cin >> n >> k;
vector<py> vec(n);
for (py& p : vec) {
cin >> p.a;
}
for (py& p : vec) {
cin >> p.b;
}
sort(vec.begin(), vec.end(), [&](py p1, py p2) {
return p1.a < p2.a;
});
vector<long long> sum(n + 1); // 前缀和 sum[i]表示0~i-1的愉悦值之和
sum[0] = 0;
for (int i = 1; i <= n; ++i) {
sum[i] = sum[i - 1] + vec[i - 1].b;
}
if (sum[n] < k) { //判断k无法满足的情况输出-1
cout << -1;
return 0;
}
int ans = 1e9;
int l = 0, r = 1;
while (r <= n) {
//右指针移动,直到愉悦值之和达到k为止
while (r <= n && sum[r] - sum[l] < k) {
++r;
}
if (r > n) break;//超出界限跳出
while (sum[r] - sum[l] >= k) {
++l; //左指针移动,直至愉悦值之和不满足k为止
}
--l; //左指针跳回上一个满足k的位置,此时得到一个最小区间,更新ans
ans = min(ans, vec[r - 1].a - vec[l].a);
++l; //左指针移动一格,搜索下一个最小区间
}
cout << ans;
}
// 64 位输出请用 printf("%lld")



京公网安备 11010502036488号