1038: [ZJOI2008]瞭望塔
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2438 Solved: 1004
[ Submit][ Status][ Discuss]
Description
致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安。我们
将H村抽象为一维的轮廓。如下图所示 我们可以用一条山的上方轮廓折线(x1, y1), (x2, y2), …. (xn, yn)来描
述H村的形状,这里x1 < x2 < …< xn。瞭望塔可以建造在[x1, xn]间的任意位置, 但必须满足从瞭望塔的顶端可
以看到H村的任意位置。可见在不同的位置建造瞭望塔,所需要建造的高度是不同的。为了节省开支,dadzhi村长
希望建造的塔高度尽可能小。请你写一个程序,帮助dadzhi村长计算塔的最小高度。
Input
第一行包含一个整数n,表示轮廓折线的节点数目。接下来第一行n个整数, 为x1 ~ xn. 第三行n个整数,为y1
~ yn。
Output
仅包含一个实数,为塔的最小高度,精确到小数点后三位。
Sample Input
6
1 2 4 5 6 7
1 2 2 4 2 1
【输入样例二】
4
10 20 49 59
0 10 10 0
Sample Output
1.000
【输出样例二】
14.500
HINT
N ≤ 300,输入坐标绝对值不超过106,注意考虑实数误差带来的问题。
Source
【分析】
根据轮廓线造出来一个下凸壳,然后大力观察得出答案一定是由顶点贡献得到的。(都是一次函数嘛)
【代码】
//bzoj 1038 [ZJOI2008]瞭望塔
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define eps 1e-8
#define inf 1e10
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=305;
int n,cnt,top;
double ans=inf;
struct point {double x,y;} p[mxn],t[mxn];
struct line {double k,b;int id;} l[mxn],s[mxn];
inline bool comp1(line l1,line l2)
{
if(fabs(l1.k-l2.k)<=eps) return l1.b<l2.b;
return l1.k<l2.k;
}
inline bool comp2(line l1,line l2) {return l1.id<l2.id;}
inline void addline(int id,double x1,double y1,double x2,double y2)
{
l[++cnt].id=id;
l[cnt].k=(y2-y1)/(x2-x1);
l[cnt].b=y1-x1*(y2-y1)/(x2-x1);
}
inline point get(line l1,line l2)
{
return (point){(l2.b-l1.b)/(l1.k-l2.k),l1.k*(l2.b-l1.b)/(l1.k-l2.k)+l1.b};
}
int main()
{
int i,j;
scanf("%d",&n);
fo(i,1,n) scanf("%lf",&p[i].x);
fo(i,1,n) scanf("%lf",&p[i].y);
fo(i,1,n-1) addline(i,p[i].x,p[i].y,p[i+1].x,p[i+1].y);
sort(l+1,l+n,comp1);cnt=0;
fo(i,1,n-1)
{
while(top && fabs(l[i].k-s[top].k)<=eps) top--;
while(top>1 && get(l[i],s[top]).x<=get(s[top],s[top-1]).x) top--;
s[++top]=l[i];
}
sort(l+1,l+n,comp2);
fo(i,1,top-1)
{
point P=get(s[i],s[i+1]);
fo(j,1,n-1)
if(P.x>=p[j].x && P.x<=p[j+1].x)
{
ans=min(ans,P.y-(l[j].k*P.x+l[j].b));
break;
}
}
fo(i,1,n)
{
point P=p[i];
fo(j,1,top)
{
point p1=get(s[j-1],s[j]),p2=get(s[j],s[j+1]);
if(j==1) p1.x=-inf;
if(j==top) p2.x=inf;
if(P.x>=p1.x && P.x<=p2.x)
{
ans=min(ans,s[j].k*P.x+s[j].b-P.y);
break;
}
}
}
printf("%.3lf\n",ans);
return 0;
}
/*
Best day of my life.
*/