UVALive - 4253 Archery 暴力

题目大意:有一个人在x轴上射箭,他能移动的范围是[0,L],现在有m个靶子,给出每个靶子的坐标(y坐标和两个x坐标),问这个人能否一箭射到所有的靶子

解题思路:二分枚举这个人所在的位置,计算一下当前位置和所有靶子的角度,维护一个角度区间,表示这个区间内的所有靶子都能射中。如果当前位置和一个靶子的角度(两个角度之间的最小值)大于当前区间的最大值,那么这个人就要向右移动,反之,如果小于当前区间的最小值,那么这个人就要向左移动

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define maxn 5010
#define esp 1e-6
struct Target{
    double y, x_l, x_r;
}t[maxn];

bool cmp(Target &a, Target &b) {
    return a.y < b.y;
}

double w;
int n;
int judge(double pos) {
    double L = atan2(t[0].y, t[0].x_r - pos);
    double R = atan2(t[0].y, t[0].x_l - pos);
    for(int i = 1; i < n; i++) {
        double l = atan2(t[i].y, t[i].x_r - pos);
        double r = atan2(t[i].y, t[i].x_l - pos);

        if(r - L < -esp) 
            return -1;
        if(l - R > esp)
            return 1;
        L = max(L, l);
        R = min(R, r);
    }
    return 0;
}

bool solve() {
    sort(t,t + n, cmp);
    double l = 0, r = w;
    int mark;
    while(r - l > esp) {
        double mid = (r + l) / 2;
        mark = judge(mid);
        if(mark == 0)
            return true;
        else if(mark == -1)
            r = mid;
        else
            l = mid;
    }
    return false;
}

int main() {
    int test;
    scanf("%d", &test);
    while(test--) {
        scanf("%lf%d", &w, &n);
        for(int i = 0; i < n; i++)
            scanf("%lf%lf%lf", &t[i].y, &t[i].x_l, &t[i].x_r);
        printf("%s\n", solve()?"YES":"NO");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值