【JZOJ3636】【BOI2012】Mobile(mobile)

Mission

著名的手机网络运营商Totalphone 修建了若干基站收发台,以用于把信号网络覆盖一条新建的高速公路。因为Totalphone 的程序员总是很马虎的,所以,基站的传功功率不能独立设置,只能将所有新基站的功率设置为一个相同的值。为了让能源的消耗尽量少,公司希望知道公路中任意点到最近基站距离的最大值。

输入的第一行包括两个整数N(1<=N<=10^6)和L(1<=L<=10^9)分别表示基站收发台的数量和高速公路的长度。接下来N行,每行包含一对整数xi,yi(-10^9<=xi,yi<=10^9)描述一个基站的坐标。所有给出的点都互不相同。点按照x坐标不下降排列。如果两个点的x坐标相同,那么它们之间按照y坐标的升序排列。

高速公路是一条从(0,0) 到(L,0) 的直线线段。

Solution

先说说O(nlog)的做法,很显然出题人是卡这种做法的。
二分答案,然后O(n)扫一遍判断n个圆是否覆盖了高速公路。


考虑到只有两点之间中垂线与公路交点(或公路端点)才有可能贡献。
我们利用一个单调栈,维护相邻的点之间的中垂线与公路交点的横坐标单调递增,
最后扫一遍栈内元素得出答案。
这里写图片描述
如图,那么B点是没有用的,因为能够贡献的区段位于E点之前,D点之后,是空集。

Code

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<math.h>
#define ll long long
#define db double
using namespace std;
const char* fin="mobile.in";
const char* fout="mobile.out";
const int inf=0x7fffffff;
const int maxn=1000007;
const db eps=10e-10;
int n,m,i,j,k;
int equ(db a,db b){return fabs(a-b)<=eps?0:(a>b?1:-1);}
struct P{
    db x,y;
    P(db _x=0,db _y=0){x=_x;y=_y;}
    P operator +(P b){return P(x+b.x,y+b.y);}
    P operator -(P b){return P(x-b.x,y-b.y);}
    P operator *(db b){return P(x*b,y*b);}
    db operator ^(P b){return x*b.y-y*b.x;}
    P per(){return P(y,-x);}
}a[maxn],b[maxn],c[maxn];
struct L{
    P p,v;
    L(){}
    L(P _p,P _v){p=_p;v=_v;}
}L0;

/*P ict(L a,L b){return b.p+b.v*(((a.p-b.p)^a.v)/(b.v^a.v));}
P x0(P a,P b){return ict(L(P((a.x+b.x)/2,(a.y+b.y)/2),(b-a).per()),L0);}*/
P x0(P a,P b){return P((b.x*b.x+b.y*b.y-a.x*a.x-a.y*a.y)/2/(b.x-a.x),0);}
db dist(P a,P b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}

int read(){
    int x=0,i=1;
    char ch=getchar();
    while (ch<'0' || ch>'9'){
        if (ch=='-') i=-1;
        ch=getchar();
    }
    while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*i;
}
int main(){
    freopen(fin,"r",stdin);
    freopen(fout,"w",stdout);
    n=read();m=read();
    L0=L(P(0,0),P(m,0));
    int N=0;
    for (i=1;i<=n;i++){
        j=read();
        k=read();
        if (!N || equ(j*1.0,a[N].x)) a[++N]=P(j,k);
        else if (abs(k)<fabs(a[N].y)) a[N].y=k;
    }
    n=N;
    db l1=10e10,l2=10e10;
    P tmp,tmd;
    N=0;
    if (n==1){
        l1=dist(L0.p,a[1]);
        l2=dist(L0.v,a[1]);
    }else{
        b[++N]=a[1];
        l1=min(l1,dist(L0.p,a[1]));
        l2=min(l2,dist(L0.v,a[1]));
        b[++N]=a[2];
        l1=min(l1,dist(L0.p,a[2]));
        l2=min(l2,dist(L0.v,a[2]));
        c[N-1]=x0(a[1],a[2]);
        for (i=3;i<=n;i++){
            while (N>1){
                tmd=x0(b[N],a[i]);
                if (equ(c[N-1].x,tmd.x)<=0) break;
                N--;
            }
            c[N]=tmd;
            b[++N]=a[i];
            l1=min(l1,dist(L0.p,a[i]));
            l2=min(l2,dist(L0.v,a[i]));
        }
    }
    db ans=max(l1,l2);
    for (i=1;i<N;i++){
        if (equ(c[i].x,0.0)>=0 && equ((c[i].x),m*1.0)<=0)
            ans=max(ans,dist(c[i],b[i]));
    }
    printf("%.3lf\n",ans);
    return 0;
}

Warning

1.卡常
1)求交时请一步得解,不要用什么向量求交。
2)读入优化。

转载于:https://www.cnblogs.com/hiweibolu/p/6714781.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值