思路
首先考虑贪心
先告诉你们一个结论:敌人最少炸坏的瞭望台总是在凸包上是连续的
怎么证明呢,如下图(我可认真了,自己画的)
如图,我们假设破坏了1点和3点,即造成了三角形125和三角形234失去保护
但是我们想如果总部在三角形125中,歹徒何必去让三角形234失去保护呢?
总部在三角形234中同理。
所以可以得出“敌人最少炸坏的瞭望台总是在凸包上是连续的”的结论(证明不太严谨,意会意会)
在考虑如何求解
我们想到二分答案
怎么来判断答案呢?
看下图QWQ
蓝色地区是1号点被破坏时,总部的安全地区
再看一个图!
蓝色地区是3号点被破坏时,总部的安全地区
2,4,5点被破坏同理
当这些蓝色的地方的交集面积大于0时,说明歹徒破坏这么多的塔,总部有地方苟活下去
怎么求交集面积呢?明显的半平面交嘛!!!
思路已经十分明了了
首先二分答案,然后用半平面交判断
优化
当你一顿操作套上了半平面交的板子时。
想要一发入魂,AC此题
然而TLE了!!!
考虑如何优化
题目给定的凸包是有序的,经过我们处理后的边同样是有序的
我们已经不需要对边按照极角排序
就优化掉了一个log
参考代码
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
struct point{
double x,y;
point(){};
point(double x,double y):x(x),y(y){};
point operator-(point b){return point(x-b.x,y-b.y);}
point operator+(point b){return point(x+b.x,y+b.y);}
point operator*(double b){return point(x*b,y*b);}
double operator%(point b){return x*b.y-y*b.x;}
}d[100005],ans[100005];
struct line{
point st,ed;
}p[100005];
point get_intersection(line s,line t){
double k=((t.ed-t.st)%(s.st-t.st))/((s.ed-s.st)%(t.ed-t.st));
return s.st+(s.ed-s.st)*k;
}
bool is_right(point a,line b){
return (a-b.st)%(b.ed-b.st)>=0;
}
int n,q[100005];
double work(){
int tt=-1,hh=0;
for(int i=1;i<=n;i++){
while(hh+1<=tt&&is_right(get_intersection(p[q[tt]],p[q[tt-1]]),p[i])) tt--;
while(hh+1<=tt&&is_right(get_intersection(p[q[hh]],p[q[hh+1]]),p[i])) hh++;
q[++tt]=i;
}
while(hh+1<=tt&&is_right(get_intersection(p[q[tt]],p[q[tt-1]]),p[q[hh]])) tt--;
while(hh+1<=tt&&is_right(get_intersection(p[q[hh]],p[q[hh+1]]),p[q[tt]])) hh++;
q[++tt]=q[hh];
int k=0;
for(int i=hh;i<tt;i++)
ans[++k]=get_intersection(p[q[i]],p[q[i+1]]);
double res=0;
for(int i=1;i<=k;i++)
res+=ans[i]%ans[i%k+1];
return res==res?fabs(res):0;
}
double check(int mid){
for(int i=1;i<=n;i++){
p[i].st=d[i];
p[i].ed=d[(i+mid-1)%n+1];
}
return work();
}
int main(){
while(~scanf("%d",&n)){
for(int i=1;i<=n;i++)
scanf("%lf%lf",&d[n-i+1].x,&d[n-i+1].y);
int l=1,r=((n+1)>>1)+1,mid;
while(l<=r){
mid=(l+r)/2;
if(check(mid)>1e-8) l=mid+1;
else r=mid-1;
}
printf("%d\n",r);
}
return 0;
}
京公网安备 11010502036488号