#5638. 朋友题解
朋友题解
题目思路分析
1. 问题理解
我们有 N 个朋友,每个朋友 i:
- 在时间
Ci前有空(拜访必须在Ci时刻前完成)。 - 小慧计划在
S + Ti时刻拜访他(S是小慧的起床时间)。
我们需要回答 Q 次询问:
- 每次询问给出小慧的目标拜访人数
V和她的起床时间S。 - 判断在
S时刻起床,她能否至少拜访V个朋友。
2. 关键条件
拜访朋友 i 成功的条件是:
S + T_i < C_i
变形为:
S < C_i - T_i
这个条件非常重要,它告诉我们:
- 每个朋友能否被成功拜访,只与小慧的起床时间
S和一个固定值C_i - T_i有关。 - 我们可以预处理出所有朋友的
C_i - T_i,然后在查询时,只需要统计有多少个C_i - T_i大于S。
3. 预处理与排序
为了快速统计大于某个值的元素数量,我们可以:
- 预处理:计算每个朋友的
C_i - T_i,存储在数组rec[]中。 - 排序:将
rec[]数组升序排序。
排序后,所有大于某个值 S 的元素会集中在数组的右侧。
4. 查询处理
对于每次查询 (V, S):
- 我们需要找到有多少个
rec[i] > S。 - 在升序数组中,大于
S的元素的个数 =n - pos + 1,其中pos是第一个大于S的元素的下标。 - 可以用 二分查找 在
O(log n)时间内找到这个pos。
5. 时间复杂度分析
- 预处理:
- 计算
rec[]:O(N) - 排序
rec[]:O(N log N)
- 计算
- 查询:
- 每次查询二分查找:
O(log N) - 总查询时间:
O(Q log N)
- 每次查询二分查找:
总体复杂度:O(N log N + Q log N),适用于数据范围 N, Q <= 1e5。
代码详细注释
#include <bits/stdc++.h>
#define int long long // 定义 int 为 long long,防止溢出
const int N = 1e5 + 10; // 最大数据量
using namespace std;
int n, q; // n: 朋友数量, q: 查询次数
int c[N], t[N], rec[N]; // c[i]: 朋友i的空闲截止时间, t[i]: 拜访i所需时间, rec[i]: c[i]-t[i]
int v, s; // v: 目标拜访人数, s: 起床时间
// 二分查找函数: 返回大于 s 的 rec[i] 的数量
int bs(int x) {
int l = 1, r = n, ans = 0; // l: 左边界, r: 右边界, ans: 记录第一个大于 x 的位置
while (l <= r) { // 二分查找循环
int mid = (l + r) >> 1; // 计算中间位置
if (rec[mid] > x) { // 如果中间值大于 x
ans = mid; // 记录当前位置为候选答案
r = mid - 1; // 向左搜索,寻找更左边的大于 x 的值
} else { // 否则
l = mid + 1; // 向右搜索
}
}
if (ans == 0) return 0; // 如果没有找到大于 x 的值,返回 0
else return n - (ans - 1); // 否则返回大于 x 的元素数量
}
signed main() {
scanf("%lld%lld", &n, &q); // 读取朋友数量和查询次数
for (int i = 1; i <= n; i++) scanf("%lld", c + i); // 读取每个朋友的空闲截止时间
for (int i = 1; i <= n; i++) scanf("%lld", t + i); // 读取拜访每个朋友所需时间
for (int i = 1; i <= n; i++) rec[i] = c[i] - t[i]; // 计算 rec[i] = c[i] - t[i]
sort(rec + 1, rec + 1 + n); // 对 rec 数组升序排序
for (int i = 1; i <= q; i++) { // 处理每个查询
scanf("%lld%lld", &v, &s); // 读取目标人数 v 和起床时间 s
int tem = bs(s); // 计算能拜访的朋友数量
if (tem >= v) printf("YES\n"); // 如果数量 >= v,输出 YES
else printf("NO\n"); // 否则输出 NO
}
return 0;
}
总结
- 核心思路:将拜访成功的条件转化为对
C_i - T_i的统计问题。 - 优化手段:通过排序和二分查找,将每次查询的时间复杂度从
O(N)降为O(log N)。 - 代码特点:预处理简单,查询高效,适用于大规模数据。