题:http://acm.hdu.edu.cn/showproblem.php?pid=6759
题意:给定n个点,每个点在同一水平方向运动,给定n个点的起点和加速度,求运动期间有多少个点可以作为唯一最前
分析:假设点i要追上点j,那么 pi+ai∗t2/2>pj+aj∗t2/2 化简得t2/2>((-pi)-(-pj))/(ai-aj), i<j,维护这个斜率的凸包即可,在凸包上的点即为可能作为最前唯一的点,不在凸包上的点说明它再超越某一个点时已经被之前的某一个点超越了
#include<bits/stdc++.h> using namespace std; typedef long long ll; 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(){ int T; scanf("%d",&T); while(T--){ int n; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%lld%lld",&s[i].x,&s[i].y); } sort(s+1,s+1+n,cmp); int maxx=0,cnt=0; int nowi=n; while(nowi>=1){ int j=nowi; while(nowi>=2&&s[nowi-1].x==s[nowi].x)///p相同,留下最大的a nowi--; if(s[nowi].y>maxx){ if(j!=nowi&&s[nowi].y==s[nowi+1].y)///多个点同时最右,贡献设为0 g[++cnt]={s[nowi].y,-s[nowi].x,0}; else g[++cnt]={s[nowi].y,-s[nowi].x,1},maxx=s[nowi].y; } nowi--; } ///维护凸包 int tot=0; for(int i=1;i<=cnt;i++){ while(tot>=2&&(g[i].y-g[q[tot]].y)*(g[q[tot]].x-g[q[tot-1]].x)<=(g[q[tot]].y-g[q[tot-1]].y)*(g[i].x-g[q[tot]].x)) tot--; q[++tot]=i; } ll ans=0; for(int i=1;i<=tot;i++) ans+=g[q[i]].num; printf("%lld ",ans); } return 0; }