2957. 赛车
题目链接
2957. 赛车
这里有一辆赛车比赛正在进行,赛场上一共有 \(N\) 辆车,分别称为 \(g_1,g_2……g_N\)。
赛道是一条无限长的直线。
最初,\(g_i\) 位于距离起跑线前进 \(k_i\) 的位置。
比赛开始后,车辆 \(g_i\) 将会以 \(v_i\) 单位每秒的恒定速度行驶。
在这个比赛过程中,如果一辆赛车曾经处于领跑位置的话(即没有其他的赛车跑在他的前面),这辆赛车最后就可以得奖,而且比赛过程中不用担心相撞的问题。
现在给出所有赛车的起始位置和速度,你的任务就是算出那些赛车将会得奖。
输入格式
第一行有一个正整数 \(N\) 表示赛车的个数。
接下来一行给出 \(N\) 个整数,按顺序给出 \(N\) 辆赛车的起始位置。
再接下来一行给出 \(N\) 个整数,按顺序给出 \(N\) 辆赛车的恒定速度。
输出格式
输出包括两行,第一行为获奖的赛车个数。
第二行按从小到大的顺序输出获奖赛车的编号,编号之间用空格隔开,注意最后一个编号后面不要加空格。
数据范围
\(1 \le N \le 10000\),
\(0 \le k_i \le 10^9\),
\(0 \le v_i \le 10^9\)
输入样例:
4
1 1 0 0
15 16 10 20
输出样例:
3
1 2 4
解题思路
半平面交
位置公式为 \(g_i=v_t\times t+k_i\),形成很多条直线,等价于有哪些直线处于最上面,即处于半平面交的直线,另外有一点需要注意:可能某些直线的某个点处于最上面,所以当前直线过前两条直线的交点时不应该弹栈
- 时间复杂度:\(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;
}