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

 

posted @ 2020-07-23 19:25  朝暮不思  阅读(260)  评论(0编辑  收藏  举报