2957. 赛车

题目链接

2957. 赛车

这里有一辆赛车比赛正在进行,赛场上一共有 N 辆车,分别称为 g1,g2gN

赛道是一条无限长的直线。

最初,gi 位于距离起跑线前进 ki 的位置。

比赛开始后,车辆 gi 将会以 vi 单位每秒的恒定速度行驶。

在这个比赛过程中,如果一辆赛车曾经处于领跑位置的话(即没有其他的赛车跑在他的前面),这辆赛车最后就可以得奖,而且比赛过程中不用担心相撞的问题。

现在给出所有赛车的起始位置和速度,你的任务就是算出那些赛车将会得奖。

输入格式

第一行有一个正整数 N 表示赛车的个数。

接下来一行给出 N 个整数,按顺序给出 N 辆赛车的起始位置。

再接下来一行给出 N 个整数,按顺序给出 N 辆赛车的恒定速度。

输出格式

输出包括两行,第一行为获奖的赛车个数。

第二行按从小到大的顺序输出获奖赛车的编号,编号之间用空格隔开,注意最后一个编号后面不要加空格。

数据范围

1N10000,
0ki109,
0vi109

输入样例:

4 1 1 0 0 15 16 10 20

输出样例:

3 1 2 4

解题思路

半平面交

位置公式为 gi=vt×t+ki,形成很多条直线,等价于有哪些直线处于最上面,即处于半平面交的直线,另外有一点需要注意:可能某些直线的某个点处于最上面,所以当前直线过前两条直线的交点时不应该弹栈

  • 时间复杂度:O(nlogn)

代码

// Problem: 赛车 // Contest: AcWing // URL: https://www.acwing.com/problem/content/2960/ // Memory Limit: 64 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } typedef long double LD; typedef pair<LD,LD> PDD; const int N=1e4+5; const LD eps=1e-18; int n,ki[N],vi[N],cnt,res[N]; int q[N]; struct Line { PDD st,ed; vector<int> ids; }line[N]; PDD operator+(PDD a,PDD b) { return {a.fi+b.fi,a.se+b.se}; } PDD operator-(PDD a,PDD b) { return {a.fi-b.fi,a.se-b.se}; } PDD operator*(PDD a,LD t) { return {a.fi*t,a.se*t}; } LD operator*(PDD a,PDD b) { return a.fi*b.se-b.fi*a.se; } int sign(LD x) { if(fabs(x)<eps)return 0; if(x<0)return -1; return 1; } int dcmp(LD x,LD y) { if(fabs(x-y)<eps)return 0; if(x<y)return -1; return 1; } LD get_angle(Line a) { return atan2(a.ed.se-a.st.se,a.ed.fi-a.st.fi); } LD area(PDD a,PDD b,PDD c) { return (b-a)*(c-a); } bool cmp(const Line &a,const Line &b) { LD A=get_angle(a),B=get_angle(b); if(!dcmp(A,B))return area(a.st,a.ed,b.st)<0; return A<B; } PDD get_line_intersection(PDD p,PDD v,PDD q,PDD w) { PDD u=p-q; LD t=w*u/(v*w); return p+v*t; } bool on_right(Line a,Line b,Line c) { PDD o=get_line_intersection(b.st,b.ed-b.st,c.st,c.ed-c.st); return sign(area(a.st,a.ed,o))<0; } void half_plane_intersection() { sort(line+1,line+1+cnt,cmp); int hh=0,tt=-1; for(int i=1;i<=cnt;i++) { if(i>1&&!dcmp(get_angle(line[i-1]),get_angle(line[i])))continue; while(hh+1<=tt&&on_right(line[i],line[q[tt-1]],line[q[tt]]))tt--; while(hh+1<=tt&&on_right(line[i],line[q[hh]],line[q[hh+1]]))hh++; q[++tt]=i; } while(hh+1<=tt&&on_right(line[hh],line[q[tt-1]],line[q[tt]]))tt--; while(hh+1<=tt&&on_right(line[tt],line[q[hh]],line[q[hh+1]]))hh++; int k=0; for(int i=hh;i<=tt;i++) for(int id:line[q[i]].ids)res[++k]=id; sort(res+1,res+1+k); cout<<k<<'\n'; for(int i=1;i<=k;i++)cout<<res[i]<<' '; } int main() { map<PII,vector<int>> mp; cin>>n; for(int i=1;i<=n;i++)cin>>ki[i]; for(int i=1;i<=n;i++)cin>>vi[i]; for(int i=1;i<=n;i++)mp[{ki[i],vi[i]}].pb(i); line[++cnt]={{0,0},{100000,0}}; line[++cnt]={{0,100000},{0,0}}; for(auto t:mp) line[++cnt]={{0,t.fi.fi},{1,t.fi.fi+t.fi.se},t.se}; half_plane_intersection(); return 0; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16895834.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
历史上的今天:
2021-11-16 华东交通大学2019年ACM 双基 程序设计竞赛
2021-11-16 矩阵乘法
点击右上角即可分享
微信分享提示