动态仙人掌(dinosaur )
程序员文章站
2022-06-02 12:33:43
...
【分析】
这道题在考场看到我是完全的蒙蔽的,惊人的妄想着能否用数据离散化后的dp来骗分。。。
我果然很菜。。。
好吧,对于我这种菜鸡来说,正解似乎有些难想,让我们考虑从最基本的情况开始考虑。先将所有仙人掌按p为第一关键字排序,从左向右扫。这里我们考虑一个贪心策略,如果仙人掌两两之间距离足够远,则仙人掌之间跳跃的最小高度一定为最高仙人掌的高度。 关于两个相邻的仙人掌如果可以下落再上跳,则到下一个仙人掌的高度就为它自身的高度。否则就不下落一路上升。
不难发现上述贪心策略如果碰到的下下个仙人掌的高度的高度差,大于它与下个仙人掌的距离差,就很容易出现一种无解情况。难道,这道题目贪心就无法完成 WA AC的使命吗?
再次观察题目(这就是不能好好利用题目信息的惨痛教训),稍加思考,我们发现关于每棵仙人掌的那些不可能越过的点(不考虑上下的方向),恰好关于仙人掌形成两个tan为1的等腰直角三角形,如图
这里我们可以以每个三角形的左端点为关键字排序。如果到第i棵仙人掌的左端点在原有区间的右端点的右边,区间最左边就为p[i]-h[i],最右边就为
p[i]+h[i],同时用仙人掌的高度更新最大高度。反之,就不能下落,且需要构造一个更大的三角形,以跳过这段区间中的所有仙人掌。
下方代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n;
struct node{
double p,h;
}a[301000];
bool cmp(node x,node y){
return x.p-x.h<y.p-y.h;
}
double ans=0;
int main(){
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%lf%lf",&a[i].p,&a[i].h);
if(a[i].h>a[i].p){
cout<<-1<<endl;
return 0;
}
}
sort(a+1,a+n+1,cmp);
double minn=a[1].p-a[1].h;
double maxx=a[1].p+a[1].h;
for(int i=2;i<=n;i++){
if(a[i].p-a[i].h>=maxx){
minn=a[i].p-a[i].h;
maxx=a[i].p+a[i].h;
ans=max(ans,a[i].h);
}
else{
// minn=min(minn,(a[i].p-a[i].h));
maxx=max(maxx,(a[i].p+a[i].h));
ans=max(ans,(maxx-minn)/2.0);
}
}
printf("%.1lf\n",ans);
return 0;
}