1. 程式人生 > 實用技巧 >2020杭電多校(一) Leading Robots(單調棧)

2020杭電多校(一) Leading Robots(單調棧)

觀察題目可得,所有初始位置比其他小,並且加速度也比其他小的點是永遠不會成為答案的,這些點應該要刪除,否則對後面求解有影響,之後會說明。

對於p相同的,只需保留a最大的即可,因為其他也不可能成為答案。如果最大的有多個,那麼這個點不能成為答案,因此要把他的貢獻置為0,但是這個點需要保留,因為可能影響到別的點

我們對於剩下的點,進行距離公式的替換,再移向後發現 pi+aitt/2>pj+ajtt/2,i<jpi+ai∗t∗t/2>pj+aj∗t∗t/2,i<j ,那麼就有:

tt/2>((pi)(pj))/(aiaj)。

也就是超過別人的時間就是斜率,因此維護一個下凸包,答案就是下凸包上的點,這裡明確的是,因為我們是按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; }
View Code