HDU5033 - Building(暴力,DP思想)

题目链接 HDU5033

【题意】在直线上给出n幢房子的坐标和高度,求出人站在任意没有房子的位置上时能看到的天空的角度范围;房子坐标不会重复,并且保证人站的位置至少左右各有一座房子,注意坐标和高度是实数。

【分析】只要DP思想那样记录每个点左右两边斜率最高的那个点,然后查询的时候二分找查询点在哪两个点之间,再计算一遍左右两边最大的斜率即可求出答案,因为用了这个思想DP查询时间复杂度很低的,就算有极端数据斜率全部递减也不会很慢。比赛的时候竟然想着计算每个点高度为0时的左右最高斜率,一直WA到死,后来才发现一个是要减去当前高度后的斜率。

【AC CODE】546ms

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define toj(a) (a*180.0/PI)
#define MAXN 100010
struct NODE{
    double x, h;
    bool operator<(const NODE& a) const{
        return x < a.x;
    }
}p[MAXN];
struct A{
    int x;
    double val;
}left[MAXN], right[MAXN];
const double PI = 4.0 * atan(1.0);
int n;

inline double clc_k(const NODE& a, const NODE& b){
    return (a.h-b.h)/fabs(a.x-b.x);
}
int find(double num)
{
    int l = 0, r = n-1, mid;
    while(l <= r)
    {
        mid = (l+r)>>1;
        if(p[mid].x < num) 
            l = mid+1;
        else 
            r = mid-1;
    }
    return l;
}
int main()
{
#ifdef SHY
    freopen("e:\\1.txt","r",stdin);
#endif
    int t, count = 0;
    scanf("%d%*c", &t);
    while(t--)
    {
        scanf("%d%*c", &n);
        for(int i = 0; i < n; i++)
            scanf("%lf %lf%*c", &p[i].x, &p[i].h);
        sort(p,p+n);
        left[0].x = -1, left[0].val = 0;
        for(int i = 1; i < n; i++)
        {
            int a = i-1;
            while(~left[a].x && left[a].val > clc_k(p[a], p[i]))
                a = left[a].x;
            left[i].x = a;
            left[i].val = clc_k(p[a], p[i]);
        }
        right[n-1].x = -1, right[n-1].val = 0;
        for(int i = n-2; i >= 0; i--)
        {
            int a = i+1;
            while(~right[a].x && right[a].val > clc_k(p[a], p[i]))
                a = right[a].x;
            right[i].x = a;
            right[i].val = clc_k(p[a], p[i]);
        }
        int q;
        NODE a;
        a.h = 0;
        scanf("%d%*c", &q);
        printf("Case #%d:\n", ++count);
        while(q--)
        {
            scanf("%lf%*c", &a.x);
            int rt = find(a.x);
            int lt = rt-1;
            while(~left[lt].x && left[lt].val > clc_k(p[lt], a))
                lt = left[lt].x;
            while(~right[rt].x && right[rt].val > clc_k(p[rt], a))
                rt = right[rt].x;
            printf("%.10lf\n", 180-toj(atan(clc_k(p[lt],a)))-toj(atan(clc_k(p[rt],a))));
        }
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值