1 条题解

  • 0
    @ 2026-5-5 18:18:07

    我们考虑一头奶牛能接到一个苹果的条件是什么。

    假如有一头奶牛,其出现时间为 t1t_1,位置为 x1x_1,有一个苹果,其出现时间为 t2t_2,位置为 x2x_2,那么此时奶牛能接到苹果的条件就是 x1x2t2t1\left| {x_1-x_2}\right|\le t_2-t_1,那么我们对于绝对值有一个常见 trick 就是把它拆开,原条件等价于同时满足。

    $\begin{aligned} x_1-x_2\le t_1-t_2\\ x_2-x_1\le t_1-t_2 \end{aligned}$

    移项得:

    $\begin{aligned} x_1-t_1\le x_2-t_2\\ x_1+t_1\le x_2+t_2 \end{aligned}$

    那么我们把 xi+tix_i+t_ixitix_i-t_i 作为横轴和数轴,就转化成了二维数点问题,也就是一头奶牛可以接到该点右上部分的苹果,下面考虑怎么取最优。

    我们贪心,考虑每个奶牛只取一个苹果,那我们肯定要让右上方的奶牛,即能力小的奶牛先取,因为这样可以避免能力大的奶牛抢占该奶牛能取的苹果导致不优的情况。

    于是我们将奶牛按照纵坐标为第一关键字,横坐标为第二关键字降序排序,这样编号小的奶牛先取,由于奶牛按照纵坐标排序,故我们应该让奶牛尽量取在该奶牛右侧的横坐标更小的苹果,用 multiset 容易维护。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=2e5+100;
    int n;
    struct node {
    	int tp,x,y,cnt;
    	bool operator <(const node &aa)const{
    		return x<aa.x;
    	}
    }a[N];
    bool cmp(node aa,node bb){
    	if(aa.y!=bb.y)return aa.y>bb.y;
    	return aa.x>bb.x;
    }
    multiset<node>s;
    int main(){
    	cin>>n;
    	for(int i=1;i<=n;i++){
    		int t,x;
    		cin>>a[i].tp>>t>>x>>a[i].cnt;
    		a[i].x=t+x;
    		a[i].y=t-x;
    	}
    	sort(a+1,a+1+n,cmp);
    	int ans=0;
    	for(int i=1;i<=n;i++){
    		if(a[i].tp==2){
    			s.insert(a[i]);//插入苹果 
    		}
    		else{
    			while(a[i].cnt){
    				auto pos=s.lower_bound((node){1,a[i].x,0,0});//找到该奶牛右侧横坐标最小的迭代器 
    				if(pos==s.end())break;
    				if(pos->cnt>a[i].cnt){
    					ans+=a[i].cnt;
    					s.insert((node){pos->tp,pos->x,pos->y,pos->cnt-a[i].cnt});
    					s.erase(pos);
    					break;
    				}
    				else{
    					ans+=pos->cnt;
    					a[i].cnt-=pos->cnt;
    					s.erase(pos);
    				}
    			}
    		}
    	}
    	cout<<ans;
    	return 0;
    }
    
    • 1

    信息

    ID
    7645
    时间
    2000ms
    内存
    256MiB
    难度
    9
    标签
    递交数
    9
    已通过
    5
    上传者