noip模拟18



A. 导弹袭击

考场上看见像凸包,连推柿子带胡猜了好几种都不对

正解是这样的:

柿子是 \(\displaystyle t=\frac{A}{a_i}+\frac{B}{b_i}\)

那么应该把每个点的横纵坐标取个倒数,所以 \(t=Ax+By\)

那么 \(\displaystyle y=-\frac{A}{B}x+\frac{t}{B}\)

转化成了斜率优化经典式,斜率为负要使截距最大,那么维护下凸包即可

这道题比较卡精度,把斜率式换一下,写成:


\[\frac{a_ia_j(b_i-b_j)}{b_ib_j(a_i-a_j)}\]


还有一个小优化,如果一个导弹两个速度都小,那么一定不优,直接排除掉即可

代码实现

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int n,sta[maxn],tp,mx;
bool vis[maxn],flag[maxn];
int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=x*10+ch-48;
ch=getchar();
}
return x*f;
}
struct P{
int x,y,id;
}a[maxn];
bool cmp(P a,P b){
return a.x==b.x?a.y>b.y:a.x>b.x;
}
double slope(int i,int j){
return 1.0*a[i].x*a[j].x*(a[i].y-a[j].y)/(1.0*a[i].y*a[j].y*(a[i].x-a[j].x));
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
a[i].x=read();
a[i].y=read();
a[i].id=i;
}
sort(a+1,a+n+1,cmp);
mx=0;
for(int i=1;i<=n;i++){
if(a[i].y>mx){
vis[i]=true;
mx=a[i].y;
}
}
sta[++tp]=1;
for(int i=2;i<=n;i++){
if(!vis[i])continue;
if(slope(i,sta[tp])>0)continue;
// cout<<i<<" ";
while(tp>1&&slope(i,sta[tp])<slope(sta[tp-1],sta[tp]))tp--;
sta[++tp]=i;
}
for(int i=1;i<=tp;i++){
flag[a[sta[i]].id]=true;
for(int j=sta[i]+1;j<=n&&a[j].x==a[sta[i]].x&&a[j].y==a[sta[i]].y;j++)flag[a[j].id]=true;
}
for(int i=1;i<=n;i++){
if(flag[i])printf("%d ",i);
}
return 0;
}

/*
7
6 6
5 7
3 13
4 12
2 13
12 4
3 13
*/