BZOJ 2732 HNOI 2012 射箭 半平面交

题目大意:给出一些与x轴垂直的线段,问一个经过原点的抛物线最多能按顺序经过多少条线段。

思路:总体上来说是数学题,我们来推一推。

设这个经过原点的抛物线为y = a * x ^ 2 + b * x,设一条线段的起点和终点为(x0,y1)和(x0,y2),且y2 > y1。

将x0带入到设出的抛物线中,会得到y = a * x0 ^ 2 + b * x0,这时候需要满足的是y <= y2 && y >= y1,也就是a * x0 ^ 2 + b * x0 <= y2 && y1 <= a * x0 ^ 2 + b * x0

整理一下思路,x0,y1,y2是已知量,a和b是我们设出来的量,不妨换一种写法,令x = a,y = b,k = x0,那么原不等式组就是

=> x * k ^ 2 + y * k <= y2 && x * k ^ 2 + y * k >= y1

=> x * k ^ 2 + y * k - y2 <= 0 && x * k ^2 + y * k - y1 >= 0

这样就很明显了,不等式组化成了两个半平面,之后利用半平面交判定是否存在就可以了。最外层套一个二分,时间复杂度大概是O(nlog^2n)

注意:此题卡精度,亲测1e-10会wa两个点,要1e-11以上才可以AC,同时一条直线的方向向量也要扩大n倍,否则就是被卡,别问我为什么,去给出题人寄刀片!

CODE:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 200010
#define EPS 1e-15
#define DCMP(a) (fabs(a) < EPS)
using namespace std;

struct Point{
    double x,y;

    Point(double _ = .0,double __ = .0):x(_),y(__) {}
    Point operator +(const Point &a)const {
        return Point(x + a.x,y + a.y);
    }
    Point operator -(const Point &a)const {
        return Point(x - a.x,y - a.y);
    }
    Point operator *(double a)const {
        return Point(x * a,y * a);
    }
}p[MAX];

struct Line{
    Point p,v;
    double alpha;

    Line(Point _,Point __):p(_),v(__) {
        alpha = atan2(v.y,v.x);
    }
    Line() {}
    bool operator <(const Line &a)const {
        return alpha < a.alpha;
    }
}src[MAX],line[MAX],q[MAX];

int asks;
int lines;

inline double Cross(const Point &p1,const Point &p2)
{
    return p1.x * p2.y - p1.y * p2.x;
}

inline bool OnLeft(const Point &p,const Line &l)
{
    return Cross(l.v,p - l.p) >= 0;
}

inline Point GetIntersection(const Line &l1,const Line &l2)
{
    Point u = l1.p - l2.p;
    double temp = Cross(l2.v,u) / Cross(l1.v,l2.v);
    return l1.p + l1.v * temp;
}

inline bool HalfplaneIntersection(int lines)
{
    int front = 1,tail = 1;
    q[1] = line[1];
    for(int i = 2; i <= lines; ++i) {
        while(front < tail && !OnLeft(p[tail - 1],line[i]))  --tail;
        while(front < tail && !OnLeft(p[front],line[i])) ++front;
        if(DCMP(Cross(q[tail].v,line[i].v)))
            q[tail] = OnLeft(q[tail].p,line[i]) ? q[tail]:line[i];
        else    q[++tail] = line[i];
        if(front < tail) p[tail - 1] = GetIntersection(q[tail],q[tail - 1]);
    }
    while(front < tail && !OnLeft(p[tail - 1],q[front])) --tail;
    return tail - front > 1;
}

inline bool Judge(int mid)
{
    mid <<= 1;
    memcpy(line + 1,src + 1,sizeof(Line) * mid);
    sort(line + 1,line + mid + 1);
    return HalfplaneIntersection(mid);
}

int main()
{
    cin >> asks;
    for(int i = 1; i <= asks; ++i) {
        static double x,y1,y2;
        scanf("%lf%lf%lf",&x,&y1,&y2);
        src[++lines] = Line(Point(0,y2 / x),Point(-1 / x,1));
        src[++lines] = Line(Point(0,y1 / x),Point(1 / x,-1));
    }
    int l = 1,r = asks,ans = 1;
    while(l <= r) {
        int mid = (l + r) >> 1;
        if(Judge(mid))
            ans = mid,l = mid + 1;
        else    r = mid - 1;
    }
    cout << ans << endl;
    return 0;
}
时间: 2024-11-29 11:01:52

BZOJ 2732 HNOI 2012 射箭 半平面交的相关文章

BZOJ 1137: [POI2009]Wsp 岛屿 半平面交

1137: [POI2009]Wsp 岛屿 Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special JudgeSubmit: 165  Solved: 78[Submit][Status][Discuss] Description Byteotia岛屿是一个凸多边形.城市全都在海岸上.按顺时针编号1到n.任意两个城市之间都有一条笔直的道路相连.道路相交处可以自由穿行.有一些道路被游击队控制了,不能走,但是可以经过这条道路与未被控制的道路的交点.问

bzoj2732: [HNOI2012]射箭 半平面交

这题乍一看与半平面交并没有什么卵联系,然而每个靶子都可以转化为两个半平面. scanf("%lf%lf%lf",&x,&ymin,&ymax); 于是乎就有ymin<=ax^2+bx<=ymax.(因为抛物线一定经过点(0,0),所以c=0) 考虑前一个有ax^2+bx>=ymin  <=>  ax^2+bx-ymin>=0. #define A x^2 #define B x #define C ymin #define x

bzoj 2732 射箭 半平面交

2732: [HNOI2012]射箭 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2531  Solved: 848[Submit][Status][Discuss] Description 沫沫最近在玩一个二维的射箭游戏,如下图 1 所示,这个游戏中的 x 轴在地面,第一象限中有一些竖直线段作为靶子,任意两个靶子都没有公共部分,也不会接触坐标轴.沫沫控制一个位于(0,0)的弓箭手,可以朝 0 至 90?中的任意角度(不包括 0度和 90度),

BZOJ 1038 ZJOI2008 瞭望塔 半平面交

题目大意及模拟退火题解:见 http://blog.csdn.net/popoqqq/article/details/39340759 这次用半平面交写了一遍--求出半平面交之后.枚举原图和半平面交的每一个点,求出答案就可以 #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 310 #define

BZOJ 2618 CQOI 2006 凸多边形 半平面交

题目大意:给出n个凸多边形,求这些多边形的面积的交. 思路:犯傻了..以后看到凸多边形第一时间就要想到半平面交啊..多明显啊,半天愣着没想出来. CODE: #include <cmath> #include <cstdio> #include <iomanip> #include <cstring> #include <iostream> #include <algorithm> #define MAX 6100 #define E

BZOJ 1038 ZJOI 2008 瞭望塔 半平面交

题目大意:给出一个村庄的轮廓,在这个村庄里可以在随意的地方建一个瞭望塔.这个塔须要足够高,使得可以看得村庄的全貌. 求这个瞭望塔的最小高度. 思路:对于村庄中的每一条边,瞭望塔为了看见它.必需要在这个直线左側的半平面区域.这种话为了满足全部的边的需求,做一次半平面交,瞭望塔的最高点必须在全部边的半平面交的区域内. 例如以下图例子. 全部边的半平面交区域就是上面的图形.设上面半平面的函数关系是F(x).村长的函数关系是G(x),那么问题就转化成了求一个x,使得(F(x) - G(x))最小. 这个

HDU 2297 半平面交

Run Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 640    Accepted Submission(s): 181 Problem Description Since members of Wuhan University ACM Team are lack of exercise, they plan to particip

关于半平面交

嗯,这是一个很屌的东西.可以把他想象成数学中的线性规划问题,然后自然而然得想到就可以求最优解啦. 如何求解半平面交????? 做法一:暴力枚举点,用该点切割现有的凸多边形,这样的复杂度是O(n^2) 做法二:神奇的分治O(nlogn),然而我并不会.... 做法三:参见2006年朱泽园大神发明的排序增量法:这里就暂时不给详细介绍了. 复杂度O(nlogn),如果把快速排序改成基数排序,复杂度可以进一步降为:O(n)!!!!!! 半平面交的另外一个应用是求多边形的核:可以想象成站在一个多边形的点上

计算几何 半平面交

LA 4992 && hdu 3761 Jungle Outpost 杭电的有点坑啊..一直爆内存,后来发现大白的半平面交模板那里 point *p = new point[n]; line *q = new line[n]这里出了问题,应该是在函数里面申请不了比较大的数组,所以爆内存..我在全局定义了两个数组就不会爆了.. 本来跑了17s多的,后来半平面交sort( l, l + n ) 被我注释了,就跑了9s多,LA上跑了 2s..应该是输入数据比较好,不用按照极角排序..然后就是照着