[USACO22OPEN] Apple Catching G
题目描述
天上下苹果了!在某些时刻,一定数量的苹果会落到数轴上。在某些时刻,Farmer John 的一些奶牛将到达数轴并开始接苹果。
如果一个苹果在没有奶牛接住的情况下落到数轴上,它就会永远消失。如果一头奶牛和一个苹果同时到达,奶牛就会接住苹果。每头奶牛每秒可以移动一单位距离。一旦一头奶牛接住了一个苹果,她就会离开数轴。
如果 FJ 的奶牛以最优方式合作,她们总共能接住多少个苹果?
输入格式
输入的第一行包含 $N$($1\le N\le 2\cdot 10^5$),为苹果落到数轴上的次数或 FJ 的奶牛出现的次数。
以下 $N$ 行每行包含四个整数 $q_i$,$t_i$,$x_i$ 和 $n_i$($q_i\in \{1,2\}, 0\le t_i\le 10^9, 0\le x_i\le 10^9, 1\le n_i\le 10^3$)。
- 如果 $q_i=1$,意味着 FJ 的 $n_i$ 头奶牛在 $t_i$ 时刻来到数轴上的 $x_i$ 位置。
- 如果 $q_i=2$,意味着 $n_i$ 个苹果在 $t_i$ 时刻落到了数轴上的 $x_i$ 位置。
输入保证所有有序对 $(t_i,x_i)$ 各不相同。
输出格式
输出 FJ 的奶牛总计能接住的苹果的最大数量。
样例 #1
样例输入 #1
5
2 5 10 100
2 6 0 3
2 8 10 7
1 2 4 5
1 4 7 6
样例输出 #1
10
样例 #2
样例输入 #2
5
2 5 10 100
2 6 0 3
2 8 11 7
1 2 4 5
1 4 7 6
样例输出 #2
9
提示
【样例解释 1】
在这个例子中,在 $t=5$ 时刻落地的 $100$ 个苹果均不能被接住。以下是一种接住 $10$ 个苹果的方式:
- FJ 的所有六头 $t=4$ 时刻到达的奶牛各接一个 $t=8$ 时刻落地的苹果。
- FJ 的一头 $t=2$ 时刻到达的奶牛接一个 $t=8$ 时刻落地的苹果。
- 余下三头 $t=2$ 时刻到达的奶牛各接一个 $t=6$ 时刻落地的苹果。
【样例解释 2】
再一次地,在 $t=5$ 时刻落地的苹果均不能被接住。除此之外,在 $t=2$ 时刻到达的奶牛均不能接住 $t=8$ 时刻落地的苹果。以下是一种接住 $9$ 个苹果的方式:
- FJ 的所有六头 $t=4$ 时刻到达的奶牛各接一个 $t=8$ 时刻落地的苹果。
- 余下三头 $t=2$ 时刻到达的奶牛各接一个 $t=6$ 时刻落地的苹果。
解题思路
考虑 $t_i$ 时刻 $x_i$ 位置上的奶牛可以接到哪些苹果,很明显这些苹果的 $t_j$ 和 $x_j$ 要满足 $x_j \in [ x_i - (t_j - t_i), \, x_i + (t_j - t_i) ]$,即
$$\begin{cases}
x_j \geq x_i - t_j + t_i \\
x_j \leq x_i + t_j - t_i
\end{cases}
\longrightarrow
\begin{cases}
x_j + t_j \geq x_i + t_i \\
x_j - t_j \leq x_i - t_i
\end{cases}$$
推到这里的时候卡住了,要同时满足两个条件不知道要怎么实现。其实可以先按照 $x_i - t_i$ 这个关键字从小到大排序,这样就把上式第二个条件固定了。其中在排序时对于 $x_i - t_i$ 相等的情况,应该优先让苹果排在前面,奶牛排在后面,因为现在是看奶牛能选哪些苹果。接下来只需要考虑第一个式子。
从左到右依次枚举,用一个 $\text{std::multiset}$ 来维护前缀中剩余的苹果,当枚举到苹果时直接把 $x_i + t_i$ 和苹果数量压入集合中。如果枚举到奶牛 $i$,那么集合中满足 $x_j + t_j \geq x_i + t_i$ 的苹果都可以选。从贪心的角度,我们应该按 $x_j + t_j$ 从依次小到大来选择,这是因为 $x_j + t_j$ 越小,那么能接住这些苹果的奶牛越少,现在奶牛 $i$ 能接到应该优先选择。
时间复杂度的计算,外层循环枚举 $n$ 个询问,当枚举到奶牛时又要内层循环枚举集合中的元素,看上去好像是 $O(n^2 \log{n})$ 级别的时间复杂度,实际上内层循环中每次不是把集合中的一个元素删掉(把某个时刻位置的全部苹果选完),就是把这群牛给删掉(接住的苹果达到上限),因此整个过程中内层循环执行次数是 $O(n)$ 级别的,因此时间复杂度应该是 $O(n \log{n})$。
AC 代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
const int N = 2e5 + 10;
struct Node {
int op, t, x, s;
bool operator<(Node &a) {
if (x - t != a.x - a.t) return x - t < a.x - a.t;
return op > a.op;
}
}q[N];
int main() {
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d %d %d %d", &q[i].op, &q[i].t, &q[i].x, &q[i].s);
}
sort(q, q + n);
multiset<PII> st;
int ret = 0;
for (int i = 0; i < n; i++) {
if (q[i].op == 2) {
st.insert({q[i].x + q[i].t, q[i].s});
}
else {
auto it = st.lower_bound({q[i].x + q[i].t, -1});
while (it != st.end()) {
if (q[i].s <= it->second) {
ret += q[i].s;
if (q[i].s != it->second) st.insert({it->first, it->second - q[i].s});
st.erase(it);
break;
}
else {
ret += it->second;
q[i].s -= it->second;
it = st.erase(it);
}
}
}
}
printf("%d", ret);
return 0;
}
参考资料
【题解】P8272 [USACO22OPEN] Apple Catching G:https://www.luogu.com.cn/blog/EricQian/solution-p8272
标签:10,奶牛,USACO22OPEN,Apple,数轴,le,Catching,苹果,时刻 From: https://www.cnblogs.com/onlyblues/p/17824768.html