由题意可知,饭局的隔阂值为隔阂最大的那一对朋友的隔阂,也就是所有参与饭局的朋友中财富最大的减去财富最小的。根据贪心的思想,如果邀请了其中两名成员和,那么想要让愉悦值最大,应当尽可能多的邀请财富值在两者之间的其他朋友。
将所有成员按照财富从小到大排序,就可以将题目转化为求连续区间的愉悦值之和大于等于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")