message

message

https://ac.nowcoder.com/acm/problem/16631

题意

对于直线y=ax+b,给出n个的a[i]和b[i]。m次询问,每次询问给出直线y=cx+d的c[i]和d[i],如果和给出的n个直线交点的最大横坐标>0,则输出横坐标,否则输出 No cross。

题解

y=ax+b    ①
y=cx+d    ②
联立①②得:x = - (b-d) / (a-c) = (b-d) / (-a-(-c))。
可以看出 x 就是将所有的横坐标取相反数之后点 (-a,b) 和点(-c,d) 所在的直线的斜率,那么问题就转换成了求最大斜率。
这个问题可以用凸包求解。用到了Andrew算法(没懂为啥Graham算法写出来的不对Andrew算法可以看这里:https://www.cnblogs.com/mudrobot/p/13330937.html
因为记录凸包点的数组是具有单调性的,所以可以当每次遇到(c,d)的时候在凸包集合上二分查询与所求点斜率最大的点,维护斜率的最大值。

代码

#include<bits/stdc++.h>
#define ll long long
#define eps 1e-10
using namespace std;

const ll maxn=1e5+10;

struct node
{
    double x,y;
    ll id;
}p[maxn],s[maxn];

double ans[maxn];

double cross(node a,node b,node c)
{
    return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
}

ll dcmp(double x)
{
    return fabs(x)<eps?0:x<0?-1:1;
}

bool operator <(node p1,node p2)
{
    return dcmp(p1.x-p2.x)<0||(dcmp(p1.x-p2.x)==0&&dcmp(p1.y-p2.y)<0);
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    ll n;
    cin>>n;
    for(ll i=0;i<n;i++){
        cin>>p[i].x>>p[i].y;
    }
    ll m;
    cin>>m;
    for(ll i=n;i<n+m;i++) cin>>p[i].x>>p[i].y,p[i].id=i;
    for(ll i=0;i<n+m;i++) p[i].x=-p[i].x;
    sort(p,p+n+m);
    ll top=0;
    for(ll i=0;i<n+m;i++){
        if(p[i].id){
            if(!top) continue;
            ll l=1,r=top;
            while(l<r){
                ll mid=l+r>>1;
                if(cross(s[mid],s[mid+1],p[i])<=0) r=mid;
                else l=mid+1;
            }
            ans[p[i].id]=max(ans[p[i].id],(p[i].y-s[l].y)/(p[i].x-s[l].x));
        }
        else{
            while(top>1&&dcmp(cross(s[top-1],s[top],p[i]))<=0) top--;
            //如果是向右转,这个中间点就不是我们要找的点
            s[++top]=p[i];//如果是向左转,就加进来
        }
    }
    reverse(p,p+n+m);
    top=0;
    for(ll i=0;i<n+m;i++){
        if(p[i].id){
            if(!top) continue;
            ll l=1,r=top,pos=1;
            while(l<r){
                ll mid=l+r>>1;
                if(cross(s[mid],s[mid+1],p[i])<=0) r=mid;
                else l=mid+1;
            }
            ans[p[i].id]=max(ans[p[i].id],(p[i].y-s[l].y)/(p[i].x-s[l].x));
        }
        else{
            while(top>1&&dcmp(cross(s[top-1],s[top],p[i]))<=0) top--;
            //如果是向右转,这个中间点就不是我们要找的点
            s[++top]=p[i];//如果是向左转,就加进来
        }
    }
    for(ll i=n;i<m+n;i++){
        if(dcmp(ans[i])<=0) cout<<"No cross"<<endl;
        else cout<<setiosflags(ios::fixed)<<setprecision(15)<<ans[i]<<endl;
    }
    return 0;
}

全部评论

相关推荐

不愿透露姓名的神秘牛友
07-09 16:15
我应届生,去年10月份开始在这家公司实习,到今年10月份正好一年想(实习+试用期),在想要不要提前9月份就离职,这样好找工作些,但又差一个月满一年,又怕10月份国庆回来离职,容易错过了下半年的金九银十,到年底容易gap到年后
小破站_程序员YT:说这家公司不好吧,你干了快一年 说这家公司好吧,你刚毕业就想跑路说你不懂行情吧,你怕错过金九银十说 你懂行情吧,校招阶段在实习,毕业社招想换工作 哥们,我该怎么劝你留下来呢
应届生,你找到工作了吗
点赞 评论 收藏
分享
醉蟀:你不干有的是人干
点赞 评论 收藏
分享
小浪_Coding:找硬件测试,也可兼顾软测欧, 简历还可以的 ,注意排版,项目写的有条理一点, 然后个人技能多加点, 润色好简历之后就开始沟通海投了,深圳,东莞这边做硬件相关的公司还不少, 医疗类,仪器类的都可以尝试
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务