给定N个数对$(T_i,S_i)$,表示时刻$S_i$时在位置$T_i$处出现一粒糖果。有一些机器人可供使用,每个机器人可花费一单位时间向相邻位置移动。要求用最少的机器人接到全部糖果。时刻0时机器人位置可自行安排。
$1 leq N leq100000$, $0 leq S_i,T_i leq 10^9$。
好题。首先可以想到转化成二维点对的问题。
对于两点$(x,y)$和$(p,q)$,两点之间能连线的要求是$|x-p| geq |y-q|$。
要求用最少的折线覆盖所有的点。
我们只考虑时间小的向大的连边。不妨令$p<x$
不考虑相等的情况下,对$x,p$,$y,q$的大小关系进行讨论。
$left{egin{array}{l}x>p\y>qend{array}
ight.$,这时还需满足$x-p geq y-q$;
$left{egin{array}{l}x>p\y<qend{array}
ight.$,这时还需满足$x-p geq q-y$;
而如果$p>x$时
$left{egin{array}{l}p>x\y>qend{array}
ight.$或$left{egin{array}{l}p>x\q>yend{array}
ight.$
发现符合条件的两种情况都满足$x-y geq p-q$且$x+y geq p+q$。而两种不合法的均不满足两者其一。
于是就转化成了二维偏序,,,点i的两个关键字如果都比点j大则可以连边。等于也是可以的。
贪心的思路比较显然,保证$x+y$有序的前提下,找到$x-y$与小于等于当前$x-y$值,且差最小的那个。(更小的一定不更优)。如果找不到就新添加一个机器人。用set维护即可,复杂度$O(nlogn)$。
#include<bits/stdc++.h> using namespace std; const int N=100010; typedef pair<int,int> P; inline int read(){ int r=0,c=getchar(); while(!isdigit(c))c=getchar(); while(isdigit(c)) r=r*10+c-'0',c=getchar(); return r; } int ans,n;P a[N]; set<int>S; set<int>::iterator it; int main(){ ans=n=read(); for(int i=1;i<=n;i++){ int y=read(),x=read(); a[i]=P(x+y,x-y); } sort(a+1,a+n+1); for(int i=1;i<=n;i++){ int t=a[i].second; it=S.upper_bound(t); if(it!=S.begin()) S.erase(--it),ans--; S.insert(t); } printf("%d ",ans); }