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;
}
posted @ 2022-11-16 14:33  zyy2001  阅读(5)  评论(0编辑  收藏  举报