2020杭电多校(一) Leading Robots(单调栈)
观察题目可得,所有初始位置比其他小,并且加速度也比其他小的点是永远不会成为答案的,这些点应该要删除,否则对后面求解有影响,之后会说明。
对于p相同的,只需保留a最大的即可,因为其他也不可能成为答案。如果最大的有多个,那么这个点不能成为答案,因此要把他的贡献置为0,但是这个点需要保留,因为可能影响到别的点
我们对于剩下的点,进行距离公式的替换,再移向后发现 pi+ai∗t∗t/2>pj+aj∗t∗t/2,i<jpi+ai∗t∗t/2>pj+aj∗t∗t/2,i<j ,那么就有:t∗t/2>((−pi)−(−pj))/(ai−aj)。
也就是超过别人的时间就是斜率,因此维护一个下凸包,答案就是下凸包上的点,这里明确的是,因为我们是按p从小到大排序,但是是倒序读入新数组的,因此追逐的方向要从后往前看。
如果不是凸包上的点,这就意味着当前点超过前面点的时候,他后面的点早已经超过他,因此不能作为答案。
这里值得说明的是,如果之前不删掉第一种非法点,那么那些点也是在下凸包上,只是斜率为负,显然我们知道斜率不可能为负,因此在之前删掉就行。
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pll; const int N=2e5+10; const int mod=1e9+7; const int inf=0x3f3f3f3f; struct node{ ll x,y,num; }s[N],g[N]; bool cmp(node a,node b){ if(a.x==b.x) return a.y>b.y; return a.x<b.x; } int q[N]; int main(){ //ios::sync_with_stdio(false); int t; cin>>t; while(t--){ int n; scanf("%d",&n); int i,j; for(i=1;i<=n;i++){ scanf("%lld%lld",&s[i].x,&s[i].y); } sort(s+1,s+1+n,cmp); int ma=0,cnt=0; for(i=n;i>=1;i--){ j=i; while(j>=2&&s[j-1].x==s[i].x) j--; if(s[j].y>ma){ if(i==j) g[++cnt]={s[j].y,-s[j].x,1},ma=s[j].y; else if(s[j].y==s[j+1].y) g[++cnt]={s[j].y,-s[j].x,0}; else{ g[++cnt]={s[j].y,-s[j].x,1},ma=s[j].y; } } i=j; } int tt=0; for(i=1;i<=cnt;i++){ while(tt>=2&&(g[i].y-g[q[tt]].y)*(g[q[tt]].x-g[q[tt-1]].x)<=(g[q[tt]].y-g[q[tt-1]].y)*(g[i].x-g[q[tt]].x)) tt--; q[++tt]=i; } ll ans=0; for(i=1;i<=tt;i++) ans+=g[q[i]].num; printf("%lld\n",ans); } return 0; }
没有人不辛苦,只有人不喊疼