Jungle Outpost

Jungle Outpost

https://ac.nowcoder.com/acm/problem/108545

图片说明

思路

首先考虑贪心
先告诉你们一个结论:敌人最少炸坏的瞭望台总是在凸包上是连续的
怎么证明呢,如下图(我可认真了,自己画的)
图片说明
如图,我们假设破坏了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;
}
全部评论

相关推荐

04-29 18:07
常州大学 Java
寂静羽翼:兄弟我已经亲身经历了,双非没实习很多大厂还是会给笔试的,可是有的公司笔试做的好也不给面一直卡着,ssob基本看我没实习都拒绝我了,但是每天投满偶尔也能有一两场初创公司的面试,但是薪资基本在五六千
点赞 评论 收藏
分享
Rena1ssance_:对的,要是面评没太烂,勤更新简历等捞就行了,腾讯可以无限复活
点赞 评论 收藏
分享
一面052350min1.自我介绍2.在学校里的经历3.你希望测试开发岗位里的测试工作和开发工作占比是多少?4.实习拷打,详细拷打实习中做过的接口自动化项目5.为什么接口自动化项目选择pytest?6.设计测试用例会考虑哪些点?7.用过jekins的什么功能,了解过它底层的实现吗8.技术栈是?熟悉的编程语言?9.口述思路:二叉树的遍历10.手撕:二分查找11.浏览器输入url到展示页面的全流程?12.进程和线程13.死锁14.慢查询15.读过有关测试的技术书籍吗16.写测试自动化时用过python的哪些库?17.反问(作业帮直播业务,给学生直播上课之类的)&nbsp;二面052755min1.自我介绍2...
一笑而过2222:1. String和StringBuffer区别:String是不可变、线程安全(因不可变特性)的,每次操作会创建新对象,适合只读场景;StringBuffer是可变、线程安全(方法加锁)的,可直接修改对象,适用于多线程环境下频繁修改字符串的场景 。 2. Java的垃圾回收器:Java垃圾回收器是JVM自动管理内存的组件,基于分代收集理论,通过标记-清除、复制、标记-整理等算法回收不再使用的对象,常见类型有Serial、Parallel、CMS、G1等,分别适用于不同性能需求场景。 3. Java的序列化:Java序列化是将对象转换为字节序列以便存储或传输的机制,对象所属类需实现Serializable接口,反序列化可将字节流恢复为对象,常用于分布式通信、数据持久化和对象深拷贝等场景。
查看24道真题和解析 面经...
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务