P3256 [JLOI2013]赛车

本文介绍了一种解决算法竞赛中直线相交问题的方法,通过借鉴CQzhangyu的实现思路,采用速度排序结合单调栈的方式,有效判断并计算两直线是否相交及交点位置。该方法首先对直线按速度进行排序,然后维护一个单调栈,通过比较直线的速度和距离,弹出不符合条件的栈顶元素,最终得到相交直线的数量和ID。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门

如果把速度看成斜率,起始位置看成截距,这就是一个水平可见直线了……

不过这题里我实现方法借鉴了CQzhangyu大佬的,先按速度排序,然后维护一个单调栈,如果当前的人速度比栈顶大距离又比它远直接弹出栈顶,或者如果它和栈顶的交点在栈顶和之前一条直线交点的左边那么也要弹出栈顶

虽然硬说起来其实差不多就是了……

//minamoto
#include<bits/stdc++.h>
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
int read(){
    int res,f=1;char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(int x){
    if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++C]=z[Z],--Z);sr[++C]=' ';
}
const int N=10005;
struct node{int v,x,id;double cro;}p[N];
int q[N],vis[N],h,n;
inline bool operator <(node a,node b){return a.v==b.v?a.x<b.x:a.v<b.v;}
int main(){
//  freopen("testdata.in","r",stdin);
    n=read();
    fp(i,1,n)p[i].x=read();
    fp(i,1,n)p[i].v=read(),p[i].id=i;
    sort(p+1,p+1+n);
    h=0;fp(i,1,n){
        while(h&&(p[i].x>p[q[h]].x||1.0*p[q[h]].x-p[i].x<p[q[h]].cro*(p[i].v-p[q[h]].v)))--h;
        if(h&&p[i].v>p[q[h]].v)p[i].cro=1.0*(p[q[h]].x-p[i].x)/(p[i].v-p[q[h]].v);
        q[++h]=i;
    }print(h),sr[C]='\n';
    fp(i,1,h)vis[p[q[i]].id]=1;
    fp(i,1,n)if(vis[i])print(i);
    return Ot(),0;
}

转载于:https://www.cnblogs.com/bztMinamoto/p/10039387.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值