把准时条件化为 c_i - t_i > S,排序差值后用二分统计可访问农场数。
OJ: usaco
题目 ID: 1397
难度:普及-
标签:排序二分查询不等式变形usaco
日期: 2026-07-11 16:03
题意
有
她必须严格早于关闭时间到达,也就是:
每个询问给出 V S,问是否至少有
思路
先看一个小数据暴力:
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-07-11 16:03
* update_at: 2026-07-11 16:04
*/
// brute.cpp:小数据暴力解,用来帮助理解题意并辅助对拍。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1005;
int n, q;
int c[MAXN];
int t[MAXN];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> q;
for (int i = 1; i <= n; i++) {
cin >> c[i];
}
for (int i = 1; i <= n; i++) {
cin >> t[i];
}
// 小数据暴力:每个询问都检查所有农场。
for (int i = 1; i <= q; i++) {
int v, s;
cin >> v >> s;
int cnt = 0;
for (int j = 1; j <= n; j++) {
if (t[j] + s < c[j]) {
cnt++;
}
}
if (cnt >= v) {
cout << "YES\n";
} else {
cout << "NO\n";
}
}
return 0;
}暴力对每个询问扫描所有农场,直接判断 t[i] + S < c[i]。这样每个询问
把判断条件移项:
等价于:
令:
那么一次询问 (V, S) 只是在问:有多少个
以样例为例:
| i | |||
|---|---|---|---|
| 1 | 3 | 4 | -1 |
| 2 | 5 | 2 | 3 |
| 3 | 7 | 3 | 4 |
| 4 | 9 | 3 | 6 |
| 5 | 12 | 8 | 4 |
排序后得到:
text
-1 3 4 4 6例如询问 3 的数,有 4,4,6 共 YES。
代码中用 upper_bound 找到第一个大于 S 的位置,后面的元素个数就是可访问农场数。
代码
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-07-11 16:03
* update_at: 2026-07-11 16:04
*/
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 200005;
int n, q;
int c[MAXN];
int t[MAXN];
int diff_arr[MAXN]; // diff_arr[i] = c[i] - t[i]
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> q;
for (int i = 1; i <= n; i++) {
cin >> c[i];
}
for (int i = 1; i <= n; i++) {
cin >> t[i];
diff_arr[i] = c[i] - t[i];
}
sort(diff_arr + 1, diff_arr + n + 1);
for (int i = 1; i <= q; i++) {
int v, s;
cin >> v >> s;
// t[i] + S < c[i] 等价于 c[i] - t[i] > S。
int pos = upper_bound(diff_arr + 1, diff_arr + n + 1, s) - diff_arr;
int cnt = n - pos + 1;
if (cnt >= v) {
cout << "YES\n";
} else {
cout << "NO\n";
}
}
return 0;
}复杂度
排序需要
每个询问二分一次,复杂度为
总时间复杂度为
总结
本题的关键不在模拟访问过程,而在把每个农场预处理成一个阈值
询问 S 之后,只需要快速统计有多少个阈值严格大于 S。严格不等号对应代码里的 upper_bound,这是最容易写错的边界。