题目链接
这里有一辆赛车比赛正在进行,赛场上一共有 N 辆车,分别称为 g1,g2……gN。
赛道是一条无限长的直线。
最初,gi 位于距离起跑线前进 ki 的位置。
比赛开始后,车辆 gi 将会以 vi 单位每秒的恒定速度行驶。
在这个比赛过程中,如果一辆赛车曾经处于领跑位置的话(即没有其他的赛车跑在他的前面),这辆赛车最后就可以得奖,而且比赛过程中不用担心相撞的问题。
现在给出所有赛车的起始位置和速度,你的任务就是算出那些赛车将会得奖。
输入格式
第一行有一个正整数 N 表示赛车的个数。
接下来一行给出 N 个整数,按顺序给出 N 辆赛车的起始位置。
再接下来一行给出 N 个整数,按顺序给出 N 辆赛车的恒定速度。
输出格式
输出包括两行,第一行为获奖的赛车个数。
第二行按从小到大的顺序输出获奖赛车的编号,编号之间用空格隔开,注意最后一个编号后面不要加空格。
数据范围
1≤N≤10000,
0≤ki≤109,
0≤vi≤109
输入样例:
输出样例:
解题思路
半平面交
位置公式为 gi=vt×t+ki,形成很多条直线,等价于有哪些直线处于最上面,即处于半平面交的直线,另外有一点需要注意:可能某些直线的某个点处于最上面,所以当前直线过前两条直线的交点时不应该弹栈
代码
#include <bits/stdc++.h>
#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__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
2021-11-16 华东交通大学2019年ACM 双基 程序设计竞赛
2021-11-16 矩阵乘法