[USACO22OPEN] Apple Catching G

[USACO22OPEN] Apple Catching G

题目描述

天上下苹果了!在某些时刻,一定数量的苹果会落到数轴上。在某些时刻,Farmer John 的一些奶牛将到达数轴并开始接苹果。

如果一个苹果在没有奶牛接住的情况下落到数轴上,它就会永远消失。如果一头奶牛和一个苹果同时到达,奶牛就会接住苹果。每头奶牛每秒可以移动一单位距离。一旦一头奶牛接住了一个苹果,她就会离开数轴。

如果 FJ 的奶牛以最优方式合作,她们总共能接住多少个苹果?

输入格式

输入的第一行包含 N1N2105),为苹果落到数轴上的次数或 FJ 的奶牛出现的次数。

以下 N 行每行包含四个整数 qitixiniqi{1,2},0ti109,0xi109,1ni103)。

  • 如果 qi=1,意味着 FJ 的 ni 头奶牛在 ti 时刻来到数轴上的 xi 位置。
  • 如果 qi=2,意味着 ni 个苹果在 ti 时刻落到了数轴上的 xi 位置。

输入保证所有有序对 (ti,xi) 各不相同。

输出格式

输出 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 时刻落地的苹果。

 

解题思路

  考虑 ti 时刻 xi 位置上的奶牛可以接到哪些苹果,很明显这些苹果的 tjxj 要满足 xj[xi(tjti),xi+(tjti)],即

{xjxitj+tixjxi+tjti{xj+tjxi+tixjtjxiti

  推到这里的时候卡住了,要同时满足两个条件不知道要怎么实现。其实可以先按照 xiti 这个关键字从小到大排序,这样就把上式第二个条件固定了。其中在排序时对于 xiti 相等的情况,应该优先让苹果排在前面,奶牛排在后面,因为现在是看奶牛能选哪些苹果。接下来只需要考虑第一个式子。

  从左到右依次枚举,用一个 std::multiset 来维护前缀中剩余的苹果,当枚举到苹果时直接把 xi+ti 和苹果数量压入集合中。如果枚举到奶牛 i,那么集合中满足 xj+tjxi+ti 的苹果都可以选。从贪心的角度,我们应该按 xj+tj 从依次小到大来选择,这是因为 xj+tj 越小,那么能接住这些苹果的奶牛越少,现在奶牛 i 能接到应该优先选择。

  时间复杂度的计算,外层循环枚举 n 个询问,当枚举到奶牛时又要内层循环枚举集合中的元素,看上去好像是 O(n2logn) 级别的时间复杂度,实际上内层循环中每次不是把集合中的一个元素删掉(把某个时刻位置的全部苹果选完),就是把这群牛给删掉(接住的苹果达到上限),因此整个过程中内层循环执行次数是 O(n) 级别的,因此时间复杂度应该是 O(nlogn)

  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

posted @   onlyblues  阅读(43)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示