【题目】
题目描述:
这里有一辆赛车比赛正在进行,赛场上一共有 n n n 辆车,分别称为 g 1 g_1 g1, g 2 g_2 g2, … … …… ……, g n g_n gn。赛道是一条无限长的直线。最初, g i g_i gi 位于距离起跑线前进 k i k_i ki 的位置。比赛开始后,车辆 g i g_i gi 将会以 v i v_i vi 单位每秒的恒定速度行驶。在这个比赛过程中,如果一辆赛车曾经处于领跑位置的话(即没有其他的赛车跑在他的前面),这辆赛车最后就可以得奖,而且比赛过程中不用担心相撞的问题。现在给出所有赛车的起始位置和速度,你的任务就是算出那些赛车将会得奖。
输入格式:
第一行有一个正整数 n n n 表示赛车的个数。
接下来一行给出 n n n 个整数,按顺序给出 n n n 辆赛车的起始位置。
再接下来一行给出 n n n 个整数,按顺序给出 n n n 辆赛车的恒定速度。
输出格式:
输出包括两行,第一行为获奖的赛车个数。
第二行按从小到大的顺序输出获奖赛车的编号,编号之间用空格隔开,注意最后一个编号后面不要加空格。
样例数据:
输入
4
1 1 0 0
15 16 10 20
输出
3
1 2 4
备注:
【数据范围】
对于
20
%
20\%
20% 的数据,
n
≤
10
n\le10
n≤10
对于
50
%
50\%
50% 的数据,
n
≤
6000
n\le6000
n≤6000
对于
100
%
100\%
100% 的数据,
n
≤
10000
,
0
≤
k
i
≤
1
0
9
,
0
≤
v
i
≤
1
0
9
n\le10000, 0\le k_i\le10^9, 0\le v_i\le10^9
n≤10000,0≤ki≤109,0≤vi≤109
【分析】
让我们先按样例数据画一下
x
−
t
x-t
x−t 图:
其实不难发现的是,我们要维护的东西就是一个半平面交。
由于我们只能在第一象限内做半平面交,可以不用双端队列,一个普通队列就行了。
注意一些细节:
- 如果两条线的 k , b k,b k,b 都相等(即重合),都保留。
- 如果两条线只有 k k k 相等,那只保留 b b b 值大的那个。
- 如果一条线 x x x 的 k , b k,b k,b 都比另一条线 y y y 的大,那只保留 x x x。
然后按照普通的半平面交做就可以了。
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 10005
#define eps 1e-8
using namespace std;
int n,tot;
struct line
{
int k,b,id;
}l[N],q[N];
bool comp2(const line &p,const line &q){return p.id<q.id;}
bool comp1(const line &p,const line &q){return (p.k!=q.k)?p.k<q.k:p.b>q.b;}
double inter(line x,line y){return 1.0*(y.b-x.b)/(x.k-y.k);}
bool check(line i,line j,line k){return inter(i,j)>inter(i,k);}
void solve()
{
int i;
sort(l+1,l+n+1,comp1);
for(i=1;i<=n;++i)
{
if(l[i].k==l[i-1].k&&l[i].b<l[i-1].b)continue;
while(tot>=1&&inter(q[tot],l[i])<-eps) tot--;
while(tot>=2&&check(q[tot],q[tot-1],l[i])) tot--;
q[++tot]=l[i];
}
printf("%d\n",tot);
sort(q+1,q+tot+1,comp2);
for(i=1;i<=tot;++i)
printf("%d ",q[i].id);
}
int main()
{
int i;
scanf("%d",&n);
for(i=1;i<=n;++i) l[i].id=i;
for(i=1;i<=n;++i) scanf("%d",&l[i].b);
for(i=1;i<=n;++i) scanf("%d",&l[i].k);
solve();
return 0;
}